Open jchyb opened 1 year ago
Better minimization:
// codecs.scala
package internal
import scala.deriving._
import scala.quoted._
class Encoder[A]
object Encoder:
inline def derived[A](): Encoder[A] =
val instances = Macros.summonEncoders[Int]
new Encoder[A]
// causes the classloader to fail
def methodWithContext[A](using ctx: Context): Encoder[A] = new Encoder[A]
inline given unionEncoder[U]: Encoder[U] = ${ unionEncoderImpl[U] }
private def unionEncoderImpl[U: scala.quoted.Type](using Quotes): Expr[Encoder[U]] = '{new Encoder[U]}
// Context.scala
package internal
class Context()
object Other {
def methodCallingMacro(): Unit =
Encoder.derived[Int]()
}
// Macros.scala
package internal
import scala.quoted.*
object Macros:
inline def summonEncoders[A]: Unit = ${ summonEncodersImpl[A] }
private def summonEncodersImpl[A: Type](using Quotes): Expr[Unit] =
Expr.summon[Encoder[Int]]
'{ () }
Interestingly, if the packages are removed, the error changes into the even less descriptive SuspendException.
It looks like the Context.scala CompileationUnit becomes suspended, and after compiling the other files, when compiler returns to Context.scala it tries to inline the derived
method, for which it calls the Macros
macro, where to summon the Encoder it tries to expand the unionEncoder
by calling the MacroClassLoader to classload the Encoder, which it fails to do because of unknown (from the ClassLoader point of view, since the file Context.class was not generated yet at that point) class Context
.
Calling the failing unionEncoder
macro directly leads to a slightly different error/crash, outside of the macro expansion context:
// Context.scala
package internal
class Context()
object Other {
def methodCallingMacro(): Unit =
Encoder.unionEncoder[Int]
}
// codecs.scala
package internal
import scala.deriving._
import scala.quoted._
class Encoder[A]
object Encoder:
def methodWithContext[A](using ctx: Context): Encoder[A] = new Encoder[A]
inline def unionEncoder[U]: Encoder[U] = ${ unionEncoderImpl[U] }
private def unionEncoderImpl[U: scala.quoted.Type](using Quotes): Expr[Encoder[U]] = '{new Encoder[U]}
Compiler version
3.3.1-RC1-bin-20230518-4ffe5af-NIGHTLY 3.3.0-RC6 3.2.2 and previous (including 3.0 and 3.1 versions)
Minimized code
I was unable to minimize further.
Output (click arrow to expand)
The error disappears when the
EmptyArgs
class is moved fromContext.scala
to a separate file.Expectation
Should compile with no errors, just like it does when
EmptyArgs
is moved to a separate file.