diff --git a/CHANGELOG.md b/CHANGELOG.md index 97cb781c08..28c16a63ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ - Fix attribute printing. https://github.com/rescript-lang/rescript-compiler/pull/7025 - Fix "rescript format" with many files. https://github.com/rescript-lang/rescript-compiler/pull/7081 - Fix bigint max, min https://github.com/rescript-lang/rescript-compiler/pull/7088 +- Fix parsing issue with nested variant pattern type spreads. https://github.com/rescript-lang/rescript-compiler/pull/7080 #### :nail_care: Polish diff --git a/compiler/syntax/src/res_grammar.ml b/compiler/syntax/src/res_grammar.ml index 35a5a498da..63dc9d6c33 100644 --- a/compiler/syntax/src/res_grammar.ml +++ b/compiler/syntax/src/res_grammar.ml @@ -171,7 +171,8 @@ let is_structure_item_start = function let is_pattern_start = function | Token.Int _ | Float _ | String _ | Codepoint _ | Backtick | True | False | Minus | Plus | Lparen | Lbracket | Lbrace | List | Dict | Underscore - | Lident _ | Uident _ | Hash | Exception | Percent | Module | At -> + | DotDotDot | Lident _ | Uident _ | Hash | Exception | Percent | Module | At + -> true | _ -> false diff --git a/compiler/syntax/tests/parsing/grammar/pattern/expected/variantSpreads.res.txt b/compiler/syntax/tests/parsing/grammar/pattern/expected/variantSpreads.res.txt new file mode 100644 index 0000000000..70323d3ecf --- /dev/null +++ b/compiler/syntax/tests/parsing/grammar/pattern/expected/variantSpreads.res.txt @@ -0,0 +1,79 @@ +type nonrec a = + | One + | Two + | Three +type nonrec b = + | ... of a + | Four + | Five +type nonrec c = + | Six + | Seven +type nonrec d = + | ... of b + | ... of c +let doWithA = + ((Function$ + (fun (a : a) -> + ((match a with + | One -> Js.log {js|aaa|js} + | Two -> Js.log {js|twwwoooo|js} + | Three -> Js.log {js|threeeee|js}) + [@res.braces ]))) + [@res.arity 1]) +let doWithB = + ((Function$ + (fun (b : b) -> + ((match b with + | One -> Js.log {js|aaa|js} + | _ -> Js.log {js|twwwoooo|js}) + [@res.braces ]))) + [@res.arity 1]) +let lookup = + ((Function$ + (fun (b : b) -> + match b with + | ((#a)[@res.patVariantSpread ]) as a -> doWithA a + | Four -> Js.log {js|four|js} + | Five -> Js.log {js|five|js})) + [@res.arity 1]) +let lookup2 = + ((Function$ + (fun (d : d) -> + match d with + | ((#a)[@res.patVariantSpread ]) as a -> doWithA a + | ((#b)[@res.patVariantSpread ]) as b -> doWithB b + | Six|Seven -> Js.log {js|Got rest of d|js})) + [@res.arity 1]) +let lookupOpt = + ((Function$ + (fun (b : b option) -> + match b with + | Some (((#a)[@res.patVariantSpread ]) as a) -> doWithA a + | Some (Four) -> Js.log {js|four|js} + | Some (Five) -> Js.log {js|five|js} + | None -> Js.log {js|None|js})) + [@res.arity 1]) +module Foo = + struct + type nonrec zz = + | First + | Second + type nonrec xx = + | ... of zz + | Third + end +let doWithZ = + ((Function$ + (fun (z : Foo.zz) -> + match z with + | First -> Js.log {js|First|js} + | Second -> Js.log {js|Second|js})) + [@res.arity 1]) +let lookup3 = + ((Function$ + (fun (d : Foo.xx) -> + match d with + | ((#Foo.zz)[@res.patVariantSpread ]) as z -> Js.log z + | Third -> Js.log {js|Third|js})) + [@res.arity 1]) \ No newline at end of file diff --git a/compiler/syntax/tests/parsing/grammar/pattern/variantSpreads.res b/compiler/syntax/tests/parsing/grammar/pattern/variantSpreads.res new file mode 100644 index 0000000000..27c971c574 --- /dev/null +++ b/compiler/syntax/tests/parsing/grammar/pattern/variantSpreads.res @@ -0,0 +1,59 @@ +type a = One | Two | Three +type b = | ...a | Four | Five +type c = Six | Seven +type d = | ...b | ...c + +let doWithA = (a: a) => { + switch a { + | One => Js.log("aaa") + | Two => Js.log("twwwoooo") + | Three => Js.log("threeeee") + } +} + +let doWithB = (b: b) => { + switch b { + | One => Js.log("aaa") + | _ => Js.log("twwwoooo") + } +} + +let lookup = (b: b) => + switch b { + | ...a as a => doWithA(a) + | Four => Js.log("four") + | Five => Js.log("five") + } + +let lookup2 = (d: d) => + switch d { + | ...a as a => doWithA(a) + | ...b as b => doWithB(b) + | Six | Seven => Js.log("Got rest of d") + } + +let lookupOpt = (b: option) => + switch b { + | Some(...a as a) => doWithA(a) + | Some(Four) => Js.log("four") + | Some(Five) => Js.log("five") + | None => Js.log("None") + } + + +module Foo = { + type zz = First | Second + type xx = | ...zz | Third +} + +let doWithZ = (z: Foo.zz) => + switch z { + | First => Js.log("First") + | Second => Js.log("Second") + } + +let lookup3 = (d: Foo.xx) => + switch d { + | ...Foo.zz as z => Js.log(z) + | Third => Js.log("Third") + } diff --git a/compiler/syntax/tests/parsing/recovery/pattern/expected/list.res.txt b/compiler/syntax/tests/parsing/recovery/pattern/expected/list.res.txt index a34e205968..28a4c8b312 100644 --- a/compiler/syntax/tests/parsing/recovery/pattern/expected/list.res.txt +++ b/compiler/syntax/tests/parsing/recovery/pattern/expected/list.res.txt @@ -24,7 +24,7 @@ Syntax error! - tests/parsing/recovery/pattern/list.res:4:13 + tests/parsing/recovery/pattern/list.res:4:9-11 2 │ | list{} => () 3 │ | list{1, list{} => () @@ -32,8 +32,9 @@ 5 │ } 6 │ - I'm not sure what to parse here when looking at ",". + Did you forget a `}` here? -;;match x with | [] -> () | 1::[]::[] -> () | [] -> 1 +;;match x with | [] -> () | 1::[]::[] -> () | [] -> [%rescript.exprhole ] +;;1 ;;[3; 4] ;;() \ No newline at end of file diff --git a/tests/tests/src/VariantPatternMatchingSpreads.js b/tests/tests/src/VariantPatternMatchingSpreads.js index 8533f4c2c4..6416532a50 100644 --- a/tests/tests/src/VariantPatternMatchingSpreads.js +++ b/tests/tests/src/VariantPatternMatchingSpreads.js @@ -51,8 +51,52 @@ function lookup2(d) { } } +function lookupOpt(b) { + if (b !== undefined) { + switch (b) { + case "Four" : + console.log("four"); + return; + case "Five" : + console.log("five"); + return; + default: + return doWithA(b); + } + } else { + console.log("None"); + return; + } +} + +let Foo = {}; + +function doWithZ(z) { + if (z === "First") { + console.log("First"); + return; + } + console.log("Second"); +} + +function lookup3(d) { + switch (d) { + case "First" : + case "Second" : + console.log(d); + return; + case "Third" : + console.log("Third"); + return; + } +} + exports.doWithA = doWithA; exports.doWithB = doWithB; exports.lookup = lookup; exports.lookup2 = lookup2; +exports.lookupOpt = lookupOpt; +exports.Foo = Foo; +exports.doWithZ = doWithZ; +exports.lookup3 = lookup3; /* No side effect */ diff --git a/tests/tests/src/VariantPatternMatchingSpreads.res b/tests/tests/src/VariantPatternMatchingSpreads.res index 77c9b8fced..a549ee35a7 100644 --- a/tests/tests/src/VariantPatternMatchingSpreads.res +++ b/tests/tests/src/VariantPatternMatchingSpreads.res @@ -31,3 +31,28 @@ let lookup2 = (d: d) => | ...b as b => doWithB(b) | Six | Seven => Js.log("Got rest of d") } + +let lookupOpt = (b: option) => + switch b { + | Some(...a as a) => doWithA(a) + | Some(Four) => Js.log("four") + | Some(Five) => Js.log("five") + | None => Js.log("None") + } + +module Foo = { + type zz = First | Second + type xx = | ...zz | Third +} + +let doWithZ = (z: Foo.zz) => + switch z { + | First => Js.log("First") + | Second => Js.log("Second") + } + +let lookup3 = (d: Foo.xx) => + switch d { + | ...Foo.zz as z => Js.log(z) + | Third => Js.log("Third") + }