-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Compiler version
3.8.0-RC3, 3.7.4
Minimized code
(Scastie: https://scastie.scala-lang.org/by3NpM7vQVWNWlhY2O5Nqw)
//> using scala 3.8.0-RC3
//> using scalacOption -explain
package minimized
import scala.annotation.experimental
import scala.util.TupledFunction
type AnyFunction[+R] = (AnyRef { def tupled: ? => R }) | Function0[R] | Function1[?, R]
inline def nextMacro[A](inline a: AnyRef): A = inline a match { case xa: A => xa }
@experimental
object app {
inline def untuppledVia_Good[Tup, R](tupFn: Tup => R): AnyFunction[R] = {
compiletime.summonFrom {
case untupper: TupledFunction[? <: AnyFunction[R], Tup => R] =>
val fn = {
// this match is a no-op, but is required for code to compile
untupper match {
case y =>
y.untupled(tupFn)
}
}
nextMacro[AnyFunction[R]](fn)
}
}
inline def untuppledVia_Bad[Tup, R](tupFn: Tup => R): AnyFunction[R] = {
compiletime.summonFrom {
case untupper: TupledFunction[? <: AnyFunction[R], Tup => R] =>
val fn = {
// if the match is removed, compilation fails
untupper.untupled(tupFn)
}
nextMacro[AnyFunction[R]](fn)
}
}
@experimental @main def main(): Unit = {
println(untuppledVia_Good((x: (Int, String, Boolean)) => println(x)))
println(untuppledVia_Bad((x: (Int, String, Boolean)) => println(x)))
}
}Output
Found: _
Required: (Int, String, Boolean) => Unit-explain
Explanation
===========
Tree:
untupper.untupled(tupFn$proxy1)
I tried to show that
_
conforms to
(Int, String, Boolean) => Unit
but none of the attempts shown below succeeded:
==> _ <: (Int, String, Boolean) => Unit
==> minimized.AnyFunction[Unit] <: (Int, String, Boolean) => Unit
==> AnyRef{def tupled: ? => Unit} | (() => Unit) | (? => Unit) <: (Int, String, Boolean) => Unit
==> AnyRef{def tupled: ? => Unit} | (() => Unit) <: (Int, String, Boolean) => Unit
==> AnyRef{def tupled: ? => Unit} <: (Int, String, Boolean) => Unit = false
The tests were made under the empty constraint
println(untuppledVia((x: (Int, String, Boolean)) => println(x)))Expectation
Expected untuppledVia_Bad macro to work. Expected the no-op match on untupper to not be required and not affect anything.
Workarounds: Unwrapping val fn = { untupper.untupled(tupFn) }; nextMacro(fn) into untupper.untupled(tupFn) makes untuppledVia_Bad specifically compile, but in the maximized version of this macro I do need to pass the tree further. Note that simply wrapping with identity - identity(untupper.untupled(tupFn)) will also break compilation again.
Note: wildcards are not necessary to reproduce this, failure also happens if match uses a type variable: case untupper: TupledFunction[t, Tup => R]
Note: replacing compiletime.summonFrom with null match causes compilation to succeed