Skip to content

NoClassDefFoundError: while executing macro expansion #19601

Closed
@WojciechMazur

Description

@WojciechMazur

When trying to reproduce and minimize OpenCB failure in zio/zio-prelude Open CB logs failing due to too restrictive cyclic macro dependency which is probably a regression (it works in previous version) I've stumbled upon other, possibly related issue.

Compiler version

All Scala 3 versions

Minimized code

// main.scala
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
  }
}
// macro.scala
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]]
}

Output (click arrow to expand)

-- Error: /Users/wmazur/projects/sandbox/core.scala:40:31 ----------------------
40 |    val one: Natural =  Natural(1) // triggers macro
   |                        ^^^^^^^^^^
   |Exception occurred while executing macro expansion.
   |java.lang.NoClassDefFoundError: prelude/Assertion$
   |    at prelude.Macros$given_FromExpr_Assertion.unapply(macro.scala:19)
   |    at scala.quoted.Quotes.value(Quotes.scala:68)
   |    at scala.quoted.Quotes.value$(Quotes.scala:44)
   |    at scala.quoted.runtime.impl.QuotesImpl.value(QuotesImpl.scala:41)
   |    at prelude.Macros$.validateInlineImpl(macro.scala:9)
   |Caused by: java.lang.ClassNotFoundException: prelude.Assertion$
   |    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
   |    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
   |    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
   |    at prelude.Macros$given_FromExpr_Assertion.unapply(macro.scala:19)
   |    at scala.quoted.Quotes.value(Quotes.scala:68)
   |    at scala.quoted.Quotes.value$(Quotes.scala:44)
   |    at scala.quoted.runtime.impl.QuotesImpl.value(QuotesImpl.scala:41)
   |    at prelude.Macros$.validateInlineImpl(macro.scala:9)
   |    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   |    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
   |    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   |    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
   |    at dotty.tools.dotc.quoted.Interpreter.interpretedStaticMethodCall$$anonfun$1(Interpreter.scala:174)
   |    at dotty.tools.dotc.quoted.Interpreter.stopIfRuntimeException(Interpreter.scala:231)
   |    at dotty.tools.dotc.quoted.Interpreter.interpretedStaticMethodCall(Interpreter.scala:174)
   |    at dotty.tools.dotc.quoted.Interpreter.interpretTree(Interpreter.scala:80)
   |    at dotty.tools.dotc.transform.Splicer$SpliceInterpreter.interpretTree(Splicer.scala:266)
   |    at dotty.tools.dotc.quoted.Interpreter.interpretTree$$anonfun$2(Interpreter.scala:99)
   |    at dotty.tools.dotc.transform.Splicer$.$anonfun$2(Splicer.scala:61)
   |    at scala.Option.fold(Option.scala:263)
   |    at dotty.tools.dotc.transform.Splicer$.splice(Splicer.scala:61)
   |    at dotty.tools.dotc.inlines.Inliner.dotty$tools$dotc$inlines$Inliner$$expandMacro(Inliner.scala:1051)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedSplice(Inliner.scala:838)
   |    at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3160)
   |    at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3199)
   |    at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedUnadapted(Inliner.scala:918)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3276)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3280)
   |    at dotty.tools.dotc.typer.ReTyper.typedTyped(ReTyper.scala:65)
   |    at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3120)
   |    at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3199)
   |    at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedUnadapted(Inliner.scala:918)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3276)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3280)
   |    at dotty.tools.dotc.inlines.Inliner.inlined(Inliner.scala:680)
   |    at dotty.tools.dotc.inlines.Inlines$InlineCall.expand(Inlines.scala:481)
   |    at dotty.tools.dotc.inlines.Inlines$.inlineCall(Inlines.scala:152)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.inlineIfNeeded(Inliner.scala:914)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedApply(Inliner.scala:819)
   |    at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3115)
   |    at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3199)
   |    at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedUnadapted(Inliner.scala:918)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3276)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3280)
   |    at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3329)
   |    at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3348)
   |    at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1193)
   |    at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:1197)
   |    at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3123)
   |    at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3199)
   |    at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedUnadapted(Inliner.scala:918)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3276)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3280)
   |    at dotty.tools.dotc.typer.ReTyper.typedTyped(ReTyper.scala:65)
   |    at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3120)
   |    at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3199)
   |    at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
   |    at dotty.tools.dotc.inlines.Inliner$InlineTyper.typedUnadapted(Inliner.scala:918)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3276)
   |    at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3280)
   |    at dotty.tools.dotc.inlines.Inliner.inlined(Inliner.scala:680)
   |    at dotty.tools.dotc.inlines.Inlines$InlineCall.expand(Inlines.scala:481)
   |    at dotty.tools.dotc.inlines.Inlines$.inlineCall(Inlines.scala:152)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:96)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1595)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:67)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:90)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1256)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:58)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:109)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1600)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:67)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:90)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1256)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:58)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:109)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1600)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:67)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:90)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1256)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1611)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:67)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:98)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1254)
   |    at dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1256)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1611)
   |    at dotty.tools.dotc.ast.TreeMapWithImplicits.transform(TreeMapWithImplicits.scala:67)
   |    at dotty.tools.dotc.transform.Inlining$InliningTreeMap.transform(Inlining.scala:98)
   |    at dotty.tools.dotc.transform.Inlining$$anon$2.transform(Inlining.scala:59)
   |    at dotty.tools.dotc.transform.MacroTransform.run(MacroTransform.scala:18)
   |    at dotty.tools.dotc.transform.Inlining.run(Inlining.scala:35)
   |    at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:354)
   |    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
   |    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
   |    at scala.collection.immutable.List.foreach(List.scala:333)
   |    at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:360)
   |    at dotty.tools.dotc.transform.Inlining.runOn(Inlining.scala:39)
   |    at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:315)
   |    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
   |    at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
   |    at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
   |    at dotty.tools.dotc.Run.runPhases$1(Run.scala:337)
   |    at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:350)
   |    at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:360)
   |    at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69)
   |    at dotty.tools.dotc.Run.compileUnits(Run.scala:360)
   |    at dotty.tools.dotc.Run.compileUnits(Run.scala:267)
   |    at dotty.tools.dotc.Run.compileSuspendedUnits(Run.scala:371)
   |    at dotty.tools.dotc.Driver.finish(Driver.scala:57)
   |    at dotty.tools.dotc.Driver.doCompile(Driver.scala:38)
   |    at dotty.tools.dotc.Driver.process(Driver.scala:196)
   |    at dotty.tools.dotc.Driver.process(Driver.scala:164)
   |    at dotty.tools.dotc.Driver.process(Driver.scala:176)
   |    at dotty.tools.dotc.Driver.main(Driver.scala:206)
   |    at dotty.tools.dotc.Main.main(Main.scala)
   |
   |----------------------------------------------------------------------------
   |Inline stack trace
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |This location contains code that was inlined from core.scala:23
23 |  protected inline def validateInline(inline value: A): Unit = ${
   |                                                               ^
24 |    Macros.validateInlineImpl[A]('assertion, 'value)
25 |  }
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |This location contains code that was inlined from core.scala:23
17 |    validateInline(a1)
   |    ^^^^^^^^^^^^^^^^^^
    ----------------------------------------------------------------------------

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions