Description
Compiler version
Versions 3.2.1, 3.2.1-RC2 and 3.2.0
Minimized code
Code is available in scastie. This may be related to #16596.
import scala.compiletime.ops.int
type Count0[N,T] <: Tuple = (N,T) match
case (0,_) => EmptyTuple
case (N,String) => String *: Count0[int.-[N, 1], String]
case (N,Int) => Int *: Count0[int.-[N, 1], Int]
case (N,Float) => Float *: Count0[int.-[N, 1], Float]
case (N,Double) => Double *: Count0[int.-[N, 1], Double]
type Count1[N,T] <: Tuple = (N,T) match
case (0,T) => EmptyTuple
case (N,String) => String *: Count1[int.-[N, 1], String]
case (N,Int) => Int *: Count1[int.-[N, 1], Int]
case (N,Float) => Float *: Count1[int.-[N, 1], Float]
case (N,Double) => Double *: Count1[int.-[N, 1], Double]
transparent inline def replicateT2Fail[T](n:Int): Count1[n.type,T] =
inline if n == 0
then
EmptyTuple.asInstanceOf[Count1[n.type,T]]
else
inline val next = n - 1
// Fails, T made explicit
val tail = replicateT2Fail[T](next)
val acc = Int *: tail
acc.asInstanceOf[Count1[n.type,T]]
transparent inline def replicateT2Ok[T](n:Int): Count1[n.type,T] =
inline if n == 0
then
EmptyTuple.asInstanceOf[Count1[n.type,T]]
else
// val tail = replicate(n-1)
inline val next = n - 1
// OK, T' == Nothing?
val tail = replicateT2Ok(next)
val acc = Int *: tail
acc.asInstanceOf[Count1[n.type,T]]
val rep1Tc = replicateT2Ok[Int](3)
//summon[rep1Tc.type <:< Int *: Int *: Int *: EmptyTuple]
println(rep1Tc)
val rep1Td = replicateT2Fail[Int](3)
//summon[rep1Td.type <:< Int *: Int *: Int *: EmptyTuple]
println(rep1Td)
Note: when compiling with 3.2.1 the commented summons
above compile, but in Scastie, it fails to compile.
Output
Found: (Int, Int)
Required: Int *: Playground.Count1[(next : (2 : Int)) - (1 : Int), Int]
Found: Int.type *: Int *: Int *: Playground.Count1[(1 : Int) - (1 : Int), Int]
Required: Int.type *: Int *: Playground.Count1[(next : (2 : Int)) - (1 : Int), Int]
Expectation
As described in #16596, if Count1[N,T]
fails for N > 2
, I would expect any function that uses this match type, to fail also. Strangely enough, it doesn't.
In the example above, replicateT2Ok[T](n:Int)
I do not set [T]
explicitly in the recursive call. I would expect this to be set to to T
. However, it seems like it s set to Nothing
, hence making Count1[N,T]
and Count0[N,T]
have the same final case. I don't know why, but compilation succeeds.
In the example above, replicateT2Fail[T](n:Int)
I set [T]
explicitly in the recursive call. As expected, I get a compilation error. This error seems to be the one I get in #16596, as is expected. What I do not expect, is to have to set T
explicitly in the recursive call. I assumed the compiler would do it automatically.