Skip to content

Commit

Permalink
Fix module symbol recovery from NoClassDefFoundError
Browse files Browse the repository at this point in the history
Fixes #19601

[Cherry-picked bab74d7]
  • Loading branch information
nicolasstucki authored and WojciechMazur committed Jun 30, 2024
1 parent decde8d commit 0537c37
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
13 changes: 9 additions & 4 deletions compiler/src/dotty/tools/dotc/quoted/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,16 @@ object Interpreter:
if !ctx.compilationUnit.isSuspendable then None
else targetException match
case _: NoClassDefFoundError | _: ClassNotFoundException =>
val className = targetException.getMessage
if className eq null then None
val message = targetException.getMessage
if message eq null then None
else
val sym = staticRef(className.toTypeName).symbol
if (sym.isDefinedInCurrentRun) Some(sym) else None
val className = message.replace('/', '.')
val sym =
if className.endsWith(str.MODULE_SUFFIX) then staticRef(className.toTermName).symbol.moduleClass
else staticRef(className.toTypeName).symbol
// If the symbol does not a a position we assume that it came from the current run and it has an error
if sym.isDefinedInCurrentRun || (sym.exists && !sym.srcPos.span.exists) then Some(sym)
else None
case _ => None
}
}
Expand Down
42 changes: 42 additions & 0 deletions tests/neg-macros/i19601/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package prelude
import scala.quoted.*

object Macros {
def validateInlineImpl[A: Type](assertionExpr: Expr[Assertion[A]], a: Expr[A])(using
Quotes
): Expr[Unit] = {
import quotes.reflect.*
val crashRoot = assertionExpr.value
'{ () }

}
given [A](using Type[A]): FromExpr[Assertion[A]] with {
def unapply(assertion: Expr[Assertion[A]])(using Quotes): Option[Assertion[A]] = {
import quotes.reflect.*

assertion match {
case '{ Assertion.greaterThanOrEqualTo[A](${ LiteralUnlift(value) })($_) } =>
Some(Assertion.greaterThanOrEqualTo(value)(orderingForValue(value)))
case _ => None
}
}
}

object LiteralUnlift {
def unapply[A: Type](expr: Expr[A])(using Quotes): Option[A] = expr match {
case '{ ${ Expr(int) }: Int } => Some(int)
case '{ Int.MaxValue } => Some(Int.MaxValue.asInstanceOf[A])
case '{ Int.MinValue } => Some(Int.MinValue.asInstanceOf[A])
case '{ ${ Expr(string) }: String } => Some(string)
case '{ ${ Expr(double) }: Double } => Some(double)
case '{ ${ Expr(float) }: Float } => Some(float)
case '{ ${ Expr(long) }: Long } => Some(long)
case '{ ${ Expr(short) }: Short } => Some(short)
case '{ ${ Expr(byte) }: Byte } => Some(byte)
case '{ ${ Expr(char) }: Char } => Some(char)
case _ => None
}
}

private def orderingForValue(any: Any)(using Quotes): Ordering[Any] = null.asInstanceOf[Ordering[Any]]
}
44 changes: 44 additions & 0 deletions tests/neg-macros/i19601/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package prelude

sealed trait Assertion[-A]:
def unary_! : Assertion[A] = ???
def apply(a: A): Either[AssertionError, Unit] = ???
object Assertion:
val anything: Assertion[Any] = ???
def greaterThanOrEqualTo[A](value: A)(implicit ordering: Ordering[A]): Assertion[A] = ???

sealed trait AssertionError

abstract class NewtypeCustom[A] {
type Type
protected inline def validateInline(inline value: A): Unit

inline def apply(inline a1: A): Type = {
validateInline(a1)
a1.asInstanceOf[Type]
}
}
abstract class Newtype[A] extends NewtypeCustom[A] {
def assertion: Assertion[A] = Assertion.anything
protected inline def validateInline(inline value: A): Unit = ${
Macros.validateInlineImpl[A]('assertion, 'value)
}
}


abstract class Subtype[A] extends Newtype[A] {
type Type <: A
}


package object newtypes {
type Natural = Natural.Type
object Natural extends Subtype[Int] {

override inline def assertion = Assertion.greaterThanOrEqualTo(0)

val one: Natural = Natural(1) // triggers macro
}
}

// nopos-error: Cyclic macro dependencies in tests/pos-macros/i19601/Test.scala. Compilation stopped since no further progress can be made.

0 comments on commit 0537c37

Please sign in to comment.