Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix evaluation of private value classes in Scala 3 #511

Merged
merged 1 commit into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = new Patch(new Span(0))
| println("ok")
| }
|}
|
|class Span(val 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
Loading