rescript-compiler icon indicating copy to clipboard operation
rescript-compiler copied to clipboard

Constant folding a pattern match on an unboxed variant produces an incorrect result

Open Innf107 opened this issue 1 year ago • 2 comments

Given an unboxed variant like this, Primary has the same runtime representation as Color("primary")

@unboxed
type color =
  | @as("primary") Primary
  | @as("secondary") Secondary
  | Color(string)

This means that a function like

let f = x =>
  switch x {
  | Color(x) => x
  | _ => "not Color"
  }

somewhat surprisingly produces "not Color" when called on Color("primary").

However, the optimizer treats this like a regular variant and so constant folding f(Color("primary")) produces "primary", which differs from the result of the generated JS.

Full playground example

Innf107 avatar Aug 13 '24 10:08 Innf107

Good catch.

cristianoc avatar Aug 13 '24 10:08 cristianoc

as discussed today, there are two issues here, the wrong inlining/optimization when using a literal and the use of literal inside the "catch-all" case.

There are 3 things we could do:

  1. check if the inlining/optimization can be improved (but the semantic here is unclear anyway)
  2. raise a warning when using a catch-all case with a literal (it was not really meant to be used that way, it was designed to handle the cases not handled at compile time, otherwise the defined variant cases are here for that)
  3. even better, raise a warning only when using in the catch-all case a literal that overlaps with the existing defined variant cases

tsnobip avatar Sep 26 '24 10:09 tsnobip