Skip to content

Commit ad01d69

Browse files
Merge pull request #4025 from dotty-staging/fix-#3916
Fix #3916: Fix interpretation of boxed value classes
2 parents 2476cb4 + 9a83333 commit ad01d69

File tree

3 files changed

+38
-8
lines changed

3 files changed

+38
-8
lines changed

compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ class Interpreter(implicit ctx: Context) {
8383
val paramClasses = paramsSig(fn.symbol)
8484
val interpretedArgs = args.map(arg => interpretTreeImpl(arg, env))
8585
val constructor = getConstructor(clazz, paramClasses)
86-
interpreted(constructor.newInstance(interpretedArgs: _*))
86+
stopIfRuntimeException(constructor.newInstance(interpretedArgs: _*))
8787

8888
case _: RefTree if tree.symbol.isStatic =>
8989
val clazz = loadClass(tree.symbol.owner.companionModule.fullName)
9090
val method = getMethod(clazz, tree.symbol.name, Nil)
91-
interpreted(method.invoke(null))
91+
stopIfRuntimeException(method.invoke(null))
9292

9393
case tree: Apply =>
9494
val evaluatedPrefix = if (tree.symbol.isStatic) null else interpretPrefix(tree, env)
@@ -98,7 +98,7 @@ class Interpreter(implicit ctx: Context) {
9898
val paramClasses = paramsSig(tree.symbol)
9999
val interpretedArgs = interpretArgs(tree, env)
100100
val method = getMethod(clazz, tree.symbol.name, paramClasses)
101-
interpreted(method.invoke(evaluatedPrefix, interpretedArgs: _*))
101+
stopIfRuntimeException(method.invoke(evaluatedPrefix, interpretedArgs: _*))
102102

103103
case tree: Ident if env.contains(tree.symbol) =>
104104
env(tree.symbol)
@@ -117,11 +117,15 @@ class Interpreter(implicit ctx: Context) {
117117
case Typed(expr, _) =>
118118
interpretTreeImpl(expr, env)
119119

120-
// Getting the underlying value of a value class. The value class is evaluated as its boxed representation
121-
// as values in the interpreter are `Object`s. Therefore we just get it from the enviroment as is.
122-
case Select(qualifier, _)
120+
case Select(qualifier, name)
123121
if tree.symbol.owner.isValueClass && tree.symbol.is(ParamAccessor) && env.contains(qualifier.symbol) =>
124-
env(qualifier.symbol)
122+
val value = env(qualifier.symbol)
123+
val clazz = value.getClass
124+
if (clazz.getCanonicalName != tree.symbol.owner.showFullName) value // Already unboxed
125+
else {
126+
val method = getMethod(clazz, name, Nil)
127+
stopIfRuntimeException(method.invoke(value))
128+
}
125129

126130
case SeqLiteral(elems, _) =>
127131
elems.map(elem => interpretTreeImpl(elem, env))
@@ -189,7 +193,7 @@ class Interpreter(implicit ctx: Context) {
189193
}
190194
}
191195

192-
private def interpreted[T](thunk: => T)(implicit pos: Position): T = {
196+
private def stopIfRuntimeException[T](thunk: => T)(implicit pos: Position): T = {
193197
try thunk
194198
catch {
195199
case ex: RuntimeException =>

tests/pos/i3916/Macro_1.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted._
2+
3+
class FInterpolatorHelper(val sc: StringContext) extends AnyVal {
4+
inline def ff(arg1: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1)))
5+
inline def ff(arg1: Any, arg2: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1), '(arg2)))
6+
inline def ff(arg1: Any, arg2: Any, arg3: Any): String = ~FInterpolation.fInterpolation(sc, Seq('(arg1), '(arg2), '(arg3)))
7+
// ...
8+
}
9+
10+
object FInterpolation {
11+
private def liftSeq(args: Seq[Expr[Any]]): Expr[Seq[Any]] = args match {
12+
case x :: xs => '{ (~x) +: ~(liftSeq(xs)) }
13+
case Nil => '(Seq(): Seq[Any])
14+
}
15+
16+
def fInterpolation(sc: StringContext, args: Seq[Expr[Any]]): Expr[String] = {
17+
val str: Expr[String] = sc.parts.mkString("")
18+
val args1: Expr[Seq[Any]] = liftSeq(args)
19+
'{ (~str).format(~args1: _*) }
20+
}
21+
}

tests/pos/i3916/Test_2.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
println(new FInterpolatorHelper(StringContext("hello%s")).ff(5))
4+
}
5+
}

0 commit comments

Comments
 (0)