Let's say I have a trait with a method extended by a companion:
object Companion extends Trait
trait Trait {
def fun(first: String): String = "anything"
}
Then I try to match this code in a macro:
tree.unseal.underlyingArgument.seal match {
case vv @ '{ ($s: Trait).fun($arg) } => arg
}
When invoking the macro with the Companion as an import:
import Companion._
mac(fun("blah"))
The following compiler error occurs:
Exception occurred while executing macro expansion.
java.lang.ClassCastException: scala.Tuple1 cannot be cast to scala.Tuple2
at companionbug.Macro$.macImpl(Macro.scala:16)
The code should compile and the match should work.
Full code sample can be found here:
https://github.com/deusaquilus/companion_bug
I would like to add that this issue is very relevant to Quill because for things like query schemas, the following pattern is typically used:
import QuotationContext._
quote {
querySchema[Table]("tableName", /*... */)
}
In this case, querySchema is actually QuotationContext.querySchema. Every single method in the Quotation DSL uses this pattern.
It is interesting to note that this problem only occurs when importing from a companion. Instantiating the trait directly and then importing the methods, it will work:
val inst = new Trait {}
import inst._
mac(fun("blah")) // Matching works!
Also, there seems to be a curious workaround. If you write the companion object into a val and then import from the val, this problem does not occur:
val comp = Companion
import comp._
mac(fun("blah"))
This is very odd but will at least let me make progress for now. Definitely won't suffice for Quill users though.
@nicolasstucki @liufengyun FYI, this is the only blocking issue I have at the moment, I've got a decent workaround for everything else.
I was curious to see what happens if you use Companion.type directly. So this:
object Companion {
def fun(first: String): String = "anything"
}
Matching against this:
case vv @ '{ ($s: Companion.type).fun($arg) } =>
using this:
import Companion._
mac(fun("blah"))
This also causes the same:
java.lang.ClassCastException: scala.Tuple1 cannot be cast to scala.Tuple2
We were ignoring the thee prefix when the scrutinee did not mention it explicitly in the tree. I will add a regression test for that one.