diff --git a/compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala b/compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala index 5be936d71ee1..bad6e4aca72c 100644 --- a/compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala +++ b/compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala @@ -83,12 +83,12 @@ class Interpreter(implicit ctx: Context) { val paramClasses = paramsSig(fn.symbol) val interpretedArgs = args.map(arg => interpretTreeImpl(arg, env)) val constructor = getConstructor(clazz, paramClasses) - interpreted(constructor.newInstance(interpretedArgs: _*)) + stopIfRuntimeException(constructor.newInstance(interpretedArgs: _*)) case _: RefTree if tree.symbol.isStatic => val clazz = loadClass(tree.symbol.owner.companionModule.fullName) val method = getMethod(clazz, tree.symbol.name, Nil) - interpreted(method.invoke(null)) + stopIfRuntimeException(method.invoke(null)) case tree: Apply => val evaluatedPrefix = if (tree.symbol.isStatic) null else interpretPrefix(tree, env) @@ -98,7 +98,7 @@ class Interpreter(implicit ctx: Context) { val paramClasses = paramsSig(tree.symbol) val interpretedArgs = interpretArgs(tree, env) val method = getMethod(clazz, tree.symbol.name, paramClasses) - interpreted(method.invoke(evaluatedPrefix, interpretedArgs: _*)) + stopIfRuntimeException(method.invoke(evaluatedPrefix, interpretedArgs: _*)) case tree: Ident if env.contains(tree.symbol) => env(tree.symbol) @@ -117,11 +117,15 @@ class Interpreter(implicit ctx: Context) { case Typed(expr, _) => interpretTreeImpl(expr, env) - // Getting the underlying value of a value class. The value class is evaluated as its boxed representation - // as values in the interpreter are `Object`s. Therefore we just get it from the enviroment as is. - case Select(qualifier, _) + case Select(qualifier, name) if tree.symbol.owner.isValueClass && tree.symbol.is(ParamAccessor) && env.contains(qualifier.symbol) => - env(qualifier.symbol) + val value = env(qualifier.symbol) + val clazz = value.getClass + if (clazz.getCanonicalName != tree.symbol.owner.showFullName) value // Already unboxed + else { + val method = getMethod(clazz, name, Nil) + stopIfRuntimeException(method.invoke(value)) + } case SeqLiteral(elems, _) => elems.map(elem => interpretTreeImpl(elem, env)) @@ -189,7 +193,7 @@ class Interpreter(implicit ctx: Context) { } } - private def interpreted[T](thunk: => T)(implicit pos: Position): T = { + private def stopIfRuntimeException[T](thunk: => T)(implicit pos: Position): T = { try thunk catch { case ex: RuntimeException => diff --git a/tests/pos/i3916/Macro_1.scala b/tests/pos/i3916/Macro_1.scala new file mode 100644 index 000000000000..a981f575764a --- /dev/null +++ b/tests/pos/i3916/Macro_1.scala @@ -0,0 +1,21 @@ +import scala.quoted._ + +class FInterpolatorHelper(val sc: StringContext) extends AnyVal { + inline def ff(arg1: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1))) + inline def ff(arg1: Any, arg2: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1), '(arg2))) + inline def ff(arg1: Any, arg2: Any, arg3: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1), '(arg2), '(arg3))) + // ... +} + +object FInterpolation { + private def liftSeq(args: Seq[Expr[Any]]): Expr[Seq[Any]] = args match { + case x :: xs => '{ (~x) +: ~(liftSeq(xs)) } + case Nil => '(Seq(): Seq[Any]) + } + + def fInterpolation(sc: StringContext, args: Seq[Expr[Any]]): Expr[String] = { + val str: Expr[String] = sc.parts.mkString("") + val args1: Expr[Seq[Any]] = liftSeq(args) + '{ (~str).format(~args1: _*) } + } +} diff --git a/tests/pos/i3916/Test_2.scala b/tests/pos/i3916/Test_2.scala new file mode 100644 index 000000000000..6da6c6997794 --- /dev/null +++ b/tests/pos/i3916/Test_2.scala @@ -0,0 +1,5 @@ + object Test { + def main(args: Array[String]): Unit = { + println(new FInterpolatorHelper(StringContext("hello%s")).ff(5)) + } +}