Closed
Description
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)