question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Enum widening sabotages match types

See original GitHub issue

It looks like widening of enums gets into the way when trying to use match types on them. I guess this is expected behavior, but it is still really sad.

Compiler version

Scala 3.2.0

Minimized example

enum Target {
  case Foo(n: Int)
  case Bar(s: String)
}

enum Source {
  case Foo(n: Int)
  case Bar(s: String)
}

type resolved[T] = T match {
  case Source.Foo => Target.Foo
  case Source.Bar => Target.Bar
}

def resolve[S <: Source](src: S): resolved[S] = ???

Now, for

val foo: Target.Foo = resolve(Source.Foo(42))

the match type gets stuck since Foo will be widened to Source.

Manually annotating works

val foo: Target.Foo = resolve(Source.Foo(42) : Source.Foo)

but is infeasible in practice.

Discussion

Context: I want to use enums to model ADTs in a compiler. Different phases have different trees. Match types could really nicely tell which tree types in the source are translated to which in the next phase. Manually “downcasting” by ascribing the call does not work, since I literally would have to annotate over 1000 of such calls.

In general, I am not a big fan of the widening behavior. I do understand the design considerations, but overall would be happier without it.

(Please feel free to immediately close and mark as won’t fix 😃 )

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:15 (12 by maintainers)

github_iconTop GitHub Comments

3reactions
mbovelcommented, Nov 8, 2022

Currently, only match expressions with patterns of the form t: T can be typed as match types.

You could rewrite your example as:

enum Target {
  case Foo(n: Int)
  case Bar(s: String)
}

enum Source {
  case Foo(n: Int)
  case Bar(s: String)
}

type resolved[T] = T match {
  case Source.Foo => Target.Foo
  case Source.Bar => Target.Bar
}

object Source {
  type Cases = Source.Foo | Source.Bar
}

def resolve[S <: Source.Cases](src: S): resolved[S] = src match {
  case src: Source.Foo => Target.Foo(src.n)
  case src: Source.Bar => Target.Bar(src.s)
}

val foo: Target.Foo = resolve(Source.Foo(42))
1reaction
soronpocommented, Nov 8, 2022

Yet, considering that match types are a new thing, this really could be considered a bug and fixed without the need for any precise modifier on the type. Intuitively, the match type is supposed to work here, and a code that currently assumes otherwise (if such code exists) should be considered invalid.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Extending a enum in Java - Stack Overflow
Enum types are final by design. The reason is that each enum type should have only the elements declared in the enum (as...
Read more >
Typescript Enums and Polymorphism with Type Matching
I almost always use const enums. When using const enums the values are replaced in your code where they are used with integer...
Read more >
Enumerations - Scala 3 - EPFL
An enumeration is used to define a type consisting of a set of named values. ... This defines a new sealed class, Color...
Read more >
Extending Enums in Java - Baeldung
In this tutorial, we'll discuss extending enums in Java, including adding new constant values and new functionalities.
Read more >
Scala Enumerations - Spaghetti and Hammers
Enumeratum is a type-safe and powerful enumeration implementation for Scala that offers exhaustive pattern match warnings. import enumeratum._ ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found