Different compiler treatment for poly variants with number labels

Polymorphic variants with number labels are compiled to JS numbers.
See the following example:

type t = [ #1 | #a ]

let is_1 = str => if str == #1 { true } else { false }
let is_a = str => if str == #a { true } else { false }

The JS output for the two functions is:

function is_1(str) {
  return str === 1;
}
function is_a(str) {
  return str === "a";
}

Playground Link

This is unfortunate if you want to use coercion to convert a poly variant to a string as suggested in the docs: Polymorphic Variant | ReScript Language Manual

Example with the same type:

type t = [ #1 | #a ]

let toStr: t => string
	= a => (a :> string)

Playground Link

This throws a type Error: Type t = [#1 | #a] is not a subtype of string

It may be not an issue in most (or all?) cases, since it is easy to use pattern matching for manual type conversion or just add a non-number character to the poly variant, but I was not expecting that labels are treated differently if they consist of digits only.

However, I have two questions that I am curious about:

  1. Is there a way to make sure a poly variant consisting only of digits is interpreted as a string by the compiler? I tried #"1" or even #\"1", but it is all the same as with #1.

  2. is there a particular reason why the compiler treats numbered labels differently than other labels in polymorphic variants?

The docs say:

You can convert a poly variant to a string or int at no cost

so this may be intended behaviour.

1 Like

this is intended behaviour. you can use same coercion syntax for ints.

type t = [#1 | #2]

let x: t = #1

let y: int = (x :> int)