Skip to content

Type inference problem #12373

Closed
Closed
@jczuchnowski

Description

@jczuchnowski

Compiler version

3.0.0-RC3

Minimized code

sealed case class Column[A](name: String)

sealed trait ColumnSet {
  type Append[That <: ColumnSet] <: ColumnSet
  def ++[That <: ColumnSet](that: That): Append[That]
}

object ColumnSet {
  type Empty                  = Empty.type
  type Singleton[A]           = Cons[A, Empty]

  case object Empty extends ColumnSet {
    type Append[That <: ColumnSet] = That
    override def ++[That <: ColumnSet](that: That): Append[That] = that
  }

  sealed case class Cons[A, B <: ColumnSet](head: Column[A], tail: B) extends ColumnSet { self =>
    type Append[That <: ColumnSet] = Cons[A, tail.Append[That]]
    override def ++[That <: ColumnSet](that: That): Append[That] = Cons(head, tail ++ that)
  }

  def long(name: String): Singleton[Long]     = Cons(Column[Long](name), Empty)
  def string(name: String): Singleton[String] = Cons(Column[String](name), Empty)
}

object Example {
  import ColumnSet._
  // inferred type 3.0.0-RC3: Singleton[Long]#Append[Cons[String, Empty]]#Append[Singleton[String]]
  // inferred type 2.13.5   : Cons[Long,Cons[String,Singleton[String]]]
  val schema1 = long("id") ++ string("first_name") ++ string("last_name") 

  // inferred type 3.0.0-RC3: error
  // inferred type 2.13.5   : Cons[Long,Cons[String,Cons[String,Singleton[Long]]]]
  val schema2 = long("id") ++ string("first_name") ++ string("last_name") ++ long("age")

  // inferred type 3.0.0-RC3: Singleton[Long]#Append[Cons[String, Empty]]#Append[Singleton[String]]#Append[Cons[Long, Empty]]
  val schema3 = ((long("id") ++ string("first_name") ++ string("last_name")): Singleton[Long]#Append[ColumnSet.Cons[String, ColumnSet.Empty]]#Append[ColumnSet.Singleton[String]]) ++ long("age")
}

Output

[error] -- [E008] Not Found Error: Example.scala:39:74 
[error] 39 |  val schema2 = long("id") ++ string("first_name") ++ string("last_name") ++ long("age")
[error]    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |value ++ is not a member of com.example.ColumnSet.Singleton[Long]#Append[That]#Append[
[error]    |  com.example.ColumnSet.Singleton[String]
[error]    |]
[error]    |
[error]    |where:    That is a type variable with constraint >: com.example.ColumnSet.Singleton[String] and <: com.example.ColumnSet

Expectation

I would expect the DSL would work for any number of elements, but it fails when adding more than 3 (as seen in schema2). If I explicitly annotate part of this expression, then the compiler catches up (as in schema3).

Scala 2.13 compiles fine so I'd like to achieve the same effect in Scala 3.

I've added inferred types in comments for both Scala 3 and 2.13.

This is a problem when migrating ZIO SQL to Scala 3 (cc: @jdegoes)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions