Open
Description
Compiler version
Scala 3.3.0-RC3
Minimized code
File1:
import java.lang.invoke.MethodHandle
import scala.quoted.*
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
class FnTest:
def target(i: Int, j: Int): Int = i + j
object FnTest:
val x = 4
inline def fn() = ${
fnImpl('mh, 'x)
}
val methodType =
MethodType.methodType(classOf[Int], classOf[Int], classOf[Int])
def target(i: Int): Int = i
val mh = MethodHandles
.publicLookup()
.nn
.findVirtual(classOf[FnTest], "target", methodType)
.nn
.bindTo(FnTest())
.nn
def fnImpl(mh: Expr[MethodHandle], num: Expr[Int])(using Quotes) =
import quotes.reflect.*
val invoke = Symbol
.classSymbol("java.lang.invoke.MethodHandle")
.declaredMethod("invoke")
.head
val mhInvocation = Apply(
Select(
Inlined(
None,
Nil,
Inlined(None, Nil, mh.asTerm)
),
invoke
),
List(
Typed(
Inlined(
None,
Nil,
Repeated(
List(
Inlined(None, Nil, Inlined(None, Nil, num.asTerm)),
Inlined(None, Nil, Inlined(None, Nil, num.asTerm))
),
Inferred(TypeRepr.of[Int])
)
),
Inferred(TypeRepr.of[Seq[Int]])
)
)
)
val invocation = Inlined(
Some(TypeTree.of[FnTest.type]),
Nil,
TypeApply(
Select(
mhInvocation,
TypeRepr.of[Any].classSymbol.get.declaredMethod("asInstanceOf").head
),
List(TypeTree.of[Int])
)
).asExprOf[Int]
invocation
inline def fn2() = ${
fn2Impl('mh, 'x)
}
def fn2Impl(mh: Expr[MethodHandle], num: Expr[Int])(using Quotes) =
import quotes.reflect.*
val code = '{
$mh.invoke(${ Varargs(List(num, num)) }*).asInstanceOf[Int]
}
report.info(code.asTerm.show(using Printer.TreeStructure))
code
inline def fn3() = ${
fn3Impl('mh, 'x)
}
def fn3Impl(mh: Expr[MethodHandle], num: Expr[Int])(using Quotes) =
import quotes.reflect.*
val code = '{
$mh.invoke($num, $num).asInstanceOf[Int]
}
report.info(code.asTerm.show(using Printer.TreeStructure))
code
File2:
import scala.util.Try
@main def run() =
Try(FnTest.fn3()).recover(t => println(t.getMessage()))
Try(FnTest.fn2()).recover(t => println(t.getMessage()))
Try(FnTest.fn()).recover(t => println(t.getMessage()))
Output
expected (int,int)int but found (int[])int
expected (int,int)int but found (Seq)Object
Expectation
All three of these macros should work, while only fn3 works in practice. What this means is that to deal with n-arity invocations of invoke on MethodHandles I have to manually write out the inputs for each arity by hand.