Skip to content

Make type inference preserve user-written union types with more than two members to infer a more precise type than Matchable #11449

Closed
@bjornregnell

Description

@bjornregnell

Compiler version

Scala compiler version 3.0.0-RC1

Minimized code

I have made this light-weight utility for handling Empty values:

object Empty:
  override def toString = "Empty"  

type Empty = Empty.type 

extension [T](x: T | Empty)
  def toOption: Option[T] = x match
    case Empty => None
    case _ => Option(x.asInstanceOf[T])

  def isEmpty: Boolean = x.isInstanceOf[Empty]
  
  def nonEmpty: Boolean = !isEmpty
  
  def get: T = x match
    case Empty => (throw new NoSuchElementException("Empty.get")).asInstanceOf[T] 
    case _ => x.asInstanceOf[T]
  
  def getOrElse(default: T): T = x match
    case Empty => default 
    case _ => x.asInstanceOf[T]

Output

With this we can do nice things such as:

scala> val xs = Vector[Int | Empty](3, 4, Empty, 5)
val xs: Vector[Int | Empty] = Vector(3, 4, Empty, 5)

scala> val ys = xs.map(_.getOrElse(42))                                                             
val ys: Vector[Int] = Vector(3, 4, 42, 5)

scala> // Nice type of ys inferred - THANK YOU Scala 3 :)

But here, type inference is struggling:

scala> val xs2 = Vector[Int | String | Empty](3, "hello", Empty)          
val xs2: Vector[Int | String | Empty] = Vector(3, hello, Empty)

scala> val ys2 = xs2.map(_.getOrElse("nada"))
val ys2: Vector[Matchable] = Vector(3, hello, nada)

scala> // Not so nice type of ys2 - could this become Vector[Int | String] ?

Expectation

It would be very nice if user-written union types of more than two members were preserved, and in the example above a more precise type than Vector[Matchable] could be inferred for ys2.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions