diff --git a/CHANGELOG.md b/CHANGELOG.md index 4541f7631b..87f9cfc420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - GenType: support `@deriving(accessors)` outputs. https://github.com/rescript-lang/rescript-compiler/pull/6537 - Allow coercing ints and floats to unboxed variants that have a catch-all unboxed int or float case. https://github.com/rescript-lang/rescript-compiler/pull/6540 +- Allow tuples in untagged variants https://github.com/rescript-lang/rescript-compiler/pull/6550 #### :bug: Bug Fix diff --git a/jscomp/build_tests/super_errors/expected/UntaggedTupleAndArray.res.expected b/jscomp/build_tests/super_errors/expected/UntaggedTupleAndArray.res.expected new file mode 100644 index 0000000000..f472163a70 --- /dev/null +++ b/jscomp/build_tests/super_errors/expected/UntaggedTupleAndArray.res.expected @@ -0,0 +1,10 @@ + + We've found a bug for you! + /.../fixtures/UntaggedTupleAndArray.res:4:3-21 + + 2 │ type t = + 3 │ | Array(array) + 4 │ | Tuple((int, int)) + 5 │ + + This untagged variant definition is invalid: At most one case can be an array or tuple type. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/expected/UntaggedUnknown.res.expected b/jscomp/build_tests/super_errors/expected/UntaggedUnknown.res.expected index a961530af3..77ebe4132a 100644 --- a/jscomp/build_tests/super_errors/expected/UntaggedUnknown.res.expected +++ b/jscomp/build_tests/super_errors/expected/UntaggedUnknown.res.expected @@ -1,9 +1,9 @@ We've found a bug for you! - /.../fixtures/UntaggedUnknown.res:2:10-31 + /.../fixtures/UntaggedUnknown.res:2:10-26 1 │ @unboxed - 2 │ type t = Tuple((float, string)) | Float(float) + 2 │ type t = List(list) | Float(float) 3 │ - This untagged variant definition is invalid: Case Tuple has a payload that is not of one of the recognized shapes (object, array, etc). Then it must be the only case with payloads. \ No newline at end of file + This untagged variant definition is invalid: Case List has a payload that is not of one of the recognized shapes (object, array, etc). Then it must be the only case with payloads. \ No newline at end of file diff --git a/jscomp/build_tests/super_errors/fixtures/UntaggedTupleAndArray.res b/jscomp/build_tests/super_errors/fixtures/UntaggedTupleAndArray.res new file mode 100644 index 0000000000..266f62ad13 --- /dev/null +++ b/jscomp/build_tests/super_errors/fixtures/UntaggedTupleAndArray.res @@ -0,0 +1,4 @@ +@unboxed +type t = + | Array(array) + | Tuple((int, int)) diff --git a/jscomp/build_tests/super_errors/fixtures/UntaggedUnknown.res b/jscomp/build_tests/super_errors/fixtures/UntaggedUnknown.res index 2a043960fe..de0ae74f0a 100644 --- a/jscomp/build_tests/super_errors/fixtures/UntaggedUnknown.res +++ b/jscomp/build_tests/super_errors/fixtures/UntaggedUnknown.res @@ -1,2 +1,2 @@ @unboxed -type t = Tuple((float, string)) | Float(float) +type t = List(list) | Float(float) diff --git a/jscomp/ml/ast_untagged_variants.ml b/jscomp/ml/ast_untagged_variants.ml index 1d760f94d1..1f721eba45 100644 --- a/jscomp/ml/ast_untagged_variants.ml +++ b/jscomp/ml/ast_untagged_variants.ml @@ -47,6 +47,7 @@ let report_error ppf = (match untaggedVariant with | OnlyOneUnknown name -> "Case " ^ name ^ " has a payload that is not of one of the recognized shapes (object, array, etc). Then it must be the only case with payloads." | AtMostOneObject -> "At most one case can be an object type." + | AtMostOneInstance Array -> "At most one case can be an array or tuple type." | AtMostOneInstance i -> "At most one case can be a " ^ (Instance.to_string i) ^ " type." | AtMostOneFunction -> "At most one case can be a function type." | AtMostOneString -> "At most one case can be a string type." @@ -183,6 +184,7 @@ let get_block_type_from_typ ~env (t: Types.type_expr) : block_type option = (match type_to_instanceof_backed_obj t with | None -> None | Some instanceType -> Some (InstanceType instanceType)) + | {desc = Ttuple _} -> Some (InstanceType Array) | _ -> None let get_block_type ~env (cstr : Types.constructor_declaration) : diff --git a/jscomp/test/UntaggedVariants.js b/jscomp/test/UntaggedVariants.js index 39735c74f6..c0299611c4 100644 --- a/jscomp/test/UntaggedVariants.js +++ b/jscomp/test/UntaggedVariants.js @@ -41,13 +41,13 @@ var ListWithTuples = {}; var ListWithObjects = {}; function tuplesToObjects(l) { - if (l === undefined) { - return null; - } else { + if (Array.isArray(l)) { return { hd: l[0], tl: tuplesToObjects(l[1]) }; + } else { + return null; } } @@ -221,18 +221,18 @@ var Json = { }; function check(s, y) { - if (s === "B") { + if (!Array.isArray(s)) { return 42; } var x = s[0]; - if (x === "B") { + if (!Array.isArray(x)) { return 42; } var tmp = s[1]; - if (tmp === "B" && x !== y) { - return 41; - } else { + if (Array.isArray(tmp) || x === y) { return 42; + } else { + return 41; } } diff --git a/jscomp/test/variantsMatching.gen.tsx b/jscomp/test/variantsMatching.gen.tsx index 1f281b4510..b1344de695 100644 --- a/jscomp/test/variantsMatching.gen.tsx +++ b/jscomp/test/variantsMatching.gen.tsx @@ -16,3 +16,5 @@ export type MyNullable_t = null | undefined | a; export type MyNullableExtended_t = null | undefined | "WhyNotAnotherOne" | a; export type UntaggedWithBool_t = string | number | boolean | string; + +export type UntaggedWithTuple_t = string | [number, number, string]; diff --git a/jscomp/test/variantsMatching.js b/jscomp/test/variantsMatching.js index 2573077d54..30080878ca 100644 --- a/jscomp/test/variantsMatching.js +++ b/jscomp/test/variantsMatching.js @@ -411,6 +411,18 @@ var UntaggedWithBool = { classify: classify }; +function classify$1(x) { + if (typeof x === "string") { + return "string"; + } else { + return "tuple"; + } +} + +var UntaggedWithTuple = { + classify: classify$1 +}; + exports.toEnum = toEnum; exports.toString = toString; exports.bar = bar; @@ -429,4 +441,5 @@ exports.MyNullableExtended = MyNullableExtended; exports.TaggedUnions = TaggedUnions; exports.CustomTagNotInline = CustomTagNotInline; exports.UntaggedWithBool = UntaggedWithBool; +exports.UntaggedWithTuple = UntaggedWithTuple; /* expectSeven Not a pure module */ diff --git a/jscomp/test/variantsMatching.res b/jscomp/test/variantsMatching.res index aca376049f..7770393730 100644 --- a/jscomp/test/variantsMatching.res +++ b/jscomp/test/variantsMatching.res @@ -286,3 +286,14 @@ module UntaggedWithBool = { | Object({name}) => "Object" ++ name } } + +module UntaggedWithTuple = { + @unboxed @genType + type t = String(string) | Tuple((int, float, string)) + + let classify = x => + switch x { + | String(_) => "string" + | Tuple(_) => "tuple" + } +}