Skip to content

Commit

Permalink
Fix evaluation of value classes in Scala 3
Browse files Browse the repository at this point in the history
  • Loading branch information
adpi2 committed Jul 14, 2023
1 parent 9ec2eb1 commit ebca4c0
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,25 @@ class ResolveReflectEval(using exprCtx: ExpressionContext) extends MiniPhase:
case _ => tree

def boxIfValueClass(term: TermSymbol, tree: Tree): Tree =
atPhase(Phases.elimErasedValueTypePhase)(term.info) match
case tpe: ErasedValueType =>
boxValueClass(tpe.tycon.typeSymbol.asClass, tree)
case tpe => tree
getErasedValueType(atPhase(Phases.elimErasedValueTypePhase)(term.info)) match
case Some(erasedValueType) =>
boxValueClass(erasedValueType.tycon.typeSymbol.asClass, tree)
case None => tree

def boxValueClass(valueClass: ClassSymbol, tree: Tree): Tree =
// qualifier is null: a value class cannot be nested into a class
val ctor = valueClass.primaryConstructor.asTerm
callConstructor(nullLiteral, ctor, List(tree))

def unboxIfValueClass(term: TermSymbol, tree: Tree): Tree =
atPhase(Phases.elimErasedValueTypePhase)(term.info) match
case tpe: ErasedValueType => unboxValueClass(tree, tpe)
case tpe => tree
getErasedValueType(atPhase(Phases.elimErasedValueTypePhase)(term.info)) match
case Some(erasedValueType) => unboxValueClass(tree, erasedValueType)
case None => tree

private def getErasedValueType(tpe: Type): Option[ErasedValueType] = tpe match
case tpe: ErasedValueType => Some(tpe)
case tpe: MethodOrPoly => getErasedValueType(tpe.resultType)
case tpe => None

private def unboxValueClass(tree: Tree, tpe: ErasedValueType): Tree =
val cls = tpe.tycon.typeSymbol.asClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,33 @@ abstract class ScalaEvaluationTests(scalaVersion: ScalaVersion) extends DebugTes
// a pure expression does nothing in statement position
check(Breakpoint(8), Evaluation.successOrIgnore("m", 1, ignore = isScala2))
}

test("i425") {
val source =
"""|package example
|
|object Rewrites {
| private class Patch(var span: Span)
|
| def main(args: Array[String]): Unit = {
| val patch = Patch(Span(0))
| println("ok")
| }
|}
|
|class Span(start: Int) extends AnyVal {
| def end = start + 1
|}
|""".stripMargin
implicit val debuggee: TestingDebuggee =
TestingDebuggee.mainClass(source, "example.Rewrites", scalaVersion)
check(
Breakpoint(8),
Evaluation.success("patch.span", 0),
Evaluation.success("patch.span = new Span(1)", ()),
Evaluation.success("patch.span", 1)
)
}
}

abstract class Scala2EvaluationTests(val scalaVersion: ScalaVersion) extends ScalaEvaluationTests(scalaVersion) {
Expand Down

0 comments on commit ebca4c0

Please sign in to comment.