New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enum and equivalent class hierarchy do not generate same type signature #16470
Comments
In terms of type inference you are missing the Singleton bound for your types. Otherwise the result type would be narrowed scala> import scala.compiletime.*
|
| enum Tup:
| case EmpT
| case TCons[H <: Singleton, T <: Tup](head: H, tail: T)
|
| import Tup.*
|
| type +:[A<: Singleton,T<:Tup] = TCons[A, T]
| extension [A<: Singleton, T <: Tup] (a: A) def +: (t: T): TCons[A, T] = TCons(a, t)
|
| val tup2 = TCons(1, TCons(2, EmpT))
| val tup3 = 1 +: 2 +: EmpT
// defined class Tup
// defined alias type +:[A <: Singleton,T <: Tup] = Tup.TCons[A, T]
def +:[A <: Singleton, T <: Tup](t: T)(a: A): Tup.TCons[A, T]
val tup2: Tup = TCons(1,TCons(2,EmpT))
val tup3: Tup.TCons[1, Tup.TCons[2, Tup]] = TCons(1,TCons(2,EmpT)) without singleton type it would infer to: val tup2: Tup = TCons(1,TCons(2,EmpT))
val tup3: Tup.TCons[Int, Tup.TCons[Int, Tup]] = TCons(1,TCons(2,EmpT)) What's really interesting is the fact that apply method of Tup.TCons has the same result type as extension |
@WojciechMazur I was unaware of the singleton bound. I confirm the results above using an IDE. When using apply, I get a However, using the singleton bound on the sealed trait version, does not show the issue you describe above. Both apply and +: produce the same expected results. Thanks for the feedback. |
@odersky I think there was a similar case reported recently but I'm not sure. It seems that the main problem is widening the types which happen for enums but not for traits. My question is are enums always widened / down casted on purpose? Is it needed to simplify types for further phases or there is some other reason for that? Example: val tup1: TCons[1, TCons[2, EmpT.type]] = TCons(1, TCons(2, EmpT))
val tup2 = TCons(1, TCons(2, EmpT))
val tup3 = 1 +: 2 +: EmpT would be inferred as the following: val tup1: Tup.TCons[1, Tup.TCons[2, Tup.EmpT.type]] = TCons(1,TCons(2,EmpT))
val tup2: Tup = TCons(1,TCons(2,EmpT))
val tup3: Tup.TCons[1, Tup.TCons[2, Tup]] = TCons(1,TCons(2,EmpT)) In the compiler after the typer phase they're defined as following: val tup1: test.Tup.TCons[1.type, test.Tup.TCons[2.type, test.Tup#EmpT.type]]
=
test.Tup.TCons.apply[(1 : Int),
test.Tup.TCons[(2 : Int), (test.Tup.EmpT : test.Tup)]
](1,
test.Tup.TCons.apply[(2 : Int), (test.Tup.EmpT : test.Tup)](2,
test.Tup#EmpT
)
)
val tup2: test.Tup.TCons[Int, test.Tup.TCons[Int, test.Tup]] =
test.+:[Int, test.Tup.TCons[Int, test.Tup]](
test.+:[Int, test.Tup](test.Tup#EmpT.asInstanceOf[test.Tup#EmpT.type])(2
)
)(1)
val tup3: test.Tup =
test.Tup.TCons.apply[Int, test.Tup](1,
test.Tup.TCons.apply[Int, test.Tup](2, test.Tup#EmpT):test.Tup
):test.Tup The most important aspect here is widening exact type info using The split method is defined as inline def split[L <: Tup](inline left:L): List[String] =
inline left match
case EmpT => List("Empty")
case cons: TCons[_, _] => "NonEmpty" :: split(cons.tail) Due to the widenning of the type, at the time of inlining would see a generic type |
|
You can use a union type of the enum cases as an upper bound if you want precise types |
Compiler version
Version 2.3.1
Minimized code
I have created two examples of an HList using this Enum:
and what I assume is the equivalent case class hierarchy:
In both cases I use the same code:
The full code can be found here:
Output
I expected both examples to compile and run. However in the Enum version, in the last line I get:
Expectation
I expect both versions to generate the same type inference. My IDE shows that for the Enum version, the HLIst will have the the generic type
Tup
. For the sealed trait version, the complete definition of HList will be retained.I would also expect the HList to retain its value types. For example, My IDE shows, which I assume is what the compiler inferred:
in my opinion should be:
For the first issue this may not be a bug. If it is not, and maybe I missed it, this difference could be documented.
The second is a question. If it is warranted, I can open another issue.
TIA
The text was updated successfully, but these errors were encountered: