Closed
Description
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)
| ^^^^^^^^^^^^^^^^^^
----------------------------------------------------------------------------