Closed
Description
Compiler version
3.1.2
Minimized code
enum Format[A]:
case Str[Next](next: Format[Next]) extends Format[(String, Next)]
case Num[Next](next: Format[Next]) extends Format[(Int, Next)]
case Constant[Next](value: String, next: Format[Next]) extends Format[Next]
case Done extends Format[Unit]
def printf[A](format: Format[A], params: A): Unit = (format, params) match
case (Format.Done, ()) =>
()
case (Format.Constant(value, next), params) =>
println(value)
printf(next, params)
case (Format.Str(next), (str, rest)) =>
println(str)
printf(next, rest)
case (Format.Num(next), (i, rest)) =>
println(i)
printf(next, rest)
Output
Compilation failure, the compiler cannot convince itself that, in the Format.Str
branch, for example, A
is of type (String, ...)
(where ...
is the right type to pass to next
).
Expectation
This should compile: the compiler already knows the right types. As shown by @smarter , the following code compiles (and runs as expected):
enum Format[A]:
case Str[Next](next: Format[Next]) extends Format[(String, Next)]
case Num[Next](next: Format[Next]) extends Format[(Int, Next)]
case Constant[Next](value: String, next: Format[Next]) extends Format[Next]
case Done extends Format[Unit]
def printf[A](format: Format[A], params: A): Unit = format match
case Format.Done =>
()
case Format.Constant(value, next) =>
print(value)
printf(next, params)
case Format.Str(next) =>
print(params(0))
printf(next, params(1))
case Format.Num(next) =>
print(params(0))
printf(next, params(1))
Note that the only difference is, instead of pattern matching on the tuple, this code explicitly calls apply
on it, which somehow satisfies the compiler that everything is alright.