Closed
Description
Compiler version
3.2.1, 3.3.0-RC1-bin-20230106-d49c2d9-NIGHTLY
Minimized code
// file: ReproTransformer.scala
import scala.quoted.*
trait ReproTransformer[A, B] {
def transform(from: A): B
}
object ReproTransformer {
final class Identity[A, B >: A] extends ReproTransformer[A, B] {
def transform(from: A): B = from
}
given identity[A, B >: A]: Identity[A, B] = Identity[A, B]
inline def getTransformer[A, B]: ReproTransformer[A, B] = ${ getTransformerMacro[A, B] }
def getTransformerMacro[A, B](using quotes: Quotes, A: Type[A], B: Type[B]) = {
import quotes.reflect.*
val transformer = (A -> B) match {
case '[a] -> '[b] =>
val summoned = Expr.summon[ReproTransformer[a, b]].get
// ----------- INTERESTING STUFF STARTS HERE
summoned match {
case '{ $t: ReproTransformer[src, dest] } => t
}
// ----------- INTERESTING STUFF ENDS HERE
}
transformer.asExprOf[ReproTransformer[A, B]]
}
}
// file: usage.scala
object A {
case class AnotherCaseClass(name: String)
val errorsOut1 = ReproTransformer.getTransformer[A.AnotherCaseClass, AnotherCaseClass]
val errorsOu2 = ReproTransformer.getTransformer[AnotherCaseClass, A.AnotherCaseClass]
val works1 = ReproTransformer.getTransformer[A.AnotherCaseClass, A.AnotherCaseClass]
val works2 = ReproTransformer.getTransformer[AnotherCaseClass, AnotherCaseClass]
}
Output
[error] -- Error: /home/aleksander/repos/ducktape/ducktape/src/main/scala/io/github/arainko/ducktape/usage.scala:8:50
[error] 8 | val errorsOut1 = ReproTransformer.getTransformer[A.AnotherCaseClass, AnotherCaseClass]
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |Exception occurred while executing macro expansion.
[error] |java.lang.Exception: Expr cast exception: io.github.arainko.ducktape.ReproTransformer.identity[io.github.arainko.ducktape.A.AnotherCaseClass, B]
[error] |of type: io.github.arainko.ducktape.ReproTransformer.Identity[io.github.arainko.ducktape.A.AnotherCaseClass, B]
[error] |did not conform to type: io.github.arainko.ducktape.ReproTransformer[io.github.arainko.ducktape.A.AnotherCaseClass, io.github.arainko.ducktape.A.AnotherCaseClass]
[error] |
[error] | at scala.quoted.runtime.impl.QuotesImpl.asExprOf(QuotesImpl.scala:73)
[error] | at io.github.arainko.ducktape.ReproTransformer$.getTransformerMacro(ReproTransformer.scala:30)
[error] |
[error] |----------------------------------------------------------------------------
[error] |Inline stack trace
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from ReproTransformer.scala:16
[error] 16 | inline def getTransformer[A, B]: ReproTransformer[A, B] = ${ getTransformerMacro[A, B] }
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] ----------------------------------------------------------------------------
Expectation
An additional (irrefutable?) quote match shouldn't change the semantics of the macro and the way you refer to a type located in an object
shouldn't matter.
If you change the implementation of getTransformerMacro
to not include the additional pattern match:
def getTransformerMacro[A, B](using quotes: Quotes, A: Type[A], B: Type[B]) = {
import quotes.reflect.*
val transformer = (A -> B) match {
case '[a] -> '[b] =>
val summoned = Expr.summon[ReproTransformer[a, b]].get
// ----------- INTERESTING STUFF STARTS HERE
summoned // return the summoned Expr straight away without additional matches
// ----------- INTERESTING ends STARTS HERE
}
transformer.asExprOf[ReproTransformer[A, B]]
}
both of the usages compile properly.
Context
This issue was brought up by one of the users of ducktape here: arainko/ducktape#26, which was subsequently fixed here: arainko/ducktape#27