Skip to content

Crash when referencing nested class in macro #19856

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

Closed
Katrix opened this issue Mar 2, 2024 · 4 comments · Fixed by #19869
Closed

Crash when referencing nested class in macro #19856

Katrix opened this issue Mar 2, 2024 · 4 comments · Fixed by #19869
Labels
Milestone

Comments

@Katrix
Copy link
Contributor

Katrix commented Mar 2, 2024

Compiler version

3.3.3

Minimized code

import scala.deriving.Mirror
import scala.quoted.{Expr, Quotes, Type}

trait macroTest[A] {
  type ElemTop <: A
  type Index[_]

  case class IdxWrapper[X](idx: Index[X])

  def indexOf[X <: ElemTop: Type](x: Expr[X]): Expr[Index[X]]

  def indexOfA(a: Expr[A]): Expr[IdxWrapper[_ <: ElemTop]]
}
object macroTest {

  def derivedImpl[A: Type, ElemTypes <: Tuple: Type, Label <: String: Type, Labels <: Tuple: Type](
      using m: Expr[
        Mirror.SumOf[A] {
          type MirroredElemTypes  = ElemTypes
          type MirroredLabel      = Label
          type MirroredElemLabels = Labels
        }
      ],
      q: Quotes,
  ): macroTest[A] = new macroTest[A]:
    override type Index[_] = Int

    // Also a problem in older versions of the compiler
    override def indexOf[X <: ElemTop: Type](x: Expr[X]): Expr[Index[X]] = '{ $m.ordinal($x) }

    // Commenting out the body of this function makes the code compile
    override def indexOfA(a: Expr[A]): Expr[IdxWrapper[_ <: ElemTop]] =
      given Type[IdxWrapper] = Type.of[IdxWrapper]
      given Type[ElemTop] = Type.of[ElemTop]
      '{ new IdxWrapper(${ indexOf(a.asInstanceOf[Expr[ElemTop]]) }) }
}

Output (click arrow to expand)

[error] ## Exception when compiling 10 sources to D:\DevProjects\Stable\perspective\dotty\derivation\.jvm\target\scala-3.3.3\classes
[error] java.lang.AssertionError: assertion failed: unresolved symbols: anonymous class Object with perspective.derivation.macroTest[A] {...} (line 26) #10766 when pickling D:\DevProjects\Stable\perspective\dotty\derivation\src\main\scala\perspective\derivation\macroTest.scala
[error] scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error] dotty.tools.dotc.core.tasty.TreePickler.pickle(TreePickler.scala:829)
[error] dotty.tools.dotc.quoted.PickledQuotes$.pickle(PickledQuotes.scala:221)
[error] dotty.tools.dotc.quoted.PickledQuotes$.pickleQuote(PickledQuotes.scala:33)
[error] dotty.tools.dotc.transform.PickleQuotes$.pickleAsTasty$1(PickleQuotes.scala:308)
[error] dotty.tools.dotc.transform.PickleQuotes$.pickle(PickleQuotes.scala:392)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:99)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock$$anonfun$1$$anonfun$1(tpd.scala:1249)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1231)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1249)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1521)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1573)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1246)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:47)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1575)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformBlock(tpd.scala:1249)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1521)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:49)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1573)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1246)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:47)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1575)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.loop$2(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1244)
[error] dotty.tools.dotc.ast.tpd$TreeMapWithPreciseStatContexts.transformStats(tpd.scala:1246)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1586)
[error] dotty.tools.dotc.transform.MacroTransform$Transformer.transform(MacroTransform.scala:40)
[error] dotty.tools.dotc.transform.PickleQuotes$$anon$1.transform(PickleQuotes.scala:103)
[error] dotty.tools.dotc.transform.MacroTransform.run(MacroTransform.scala:18)
[error] dotty.tools.dotc.transform.PickleQuotes.run(PickleQuotes.scala:90)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:327)
[error] scala.collection.immutable.List.map(List.scala:246)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:331)
[error] dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:246)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] dotty.tools.dotc.Run.runPhases$1(Run.scala:262)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:270)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:279)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:71)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:279)
[error] dotty.tools.dotc.Run.compileSources(Run.scala:194)
[error] dotty.tools.dotc.Run.compile(Run.scala:179)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
[error] dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:136)
[error] dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:193)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:248)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:183)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:211)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5(Incremental.scala:180)
[error] sbt.internal.inc.Incremental$.$anonfun$apply$5$adapted(Incremental.scala:178)
[error] sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:464)
[error] sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:116)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56)
[error] sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263)
[error] sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:419)
[error] sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:506)
[error] sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:406)
[error] sbt.internal.inc.Incremental$.apply(Incremental.scala:172)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:534)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:488)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:425)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:2371)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$2(Defaults.scala:2321)
[error] sbt.internal.server.BspCompileTask$.$anonfun$compute$1(BspCompileTask.scala:31)
[error] sbt.internal.io.Retry$.apply(Retry.scala:47)
[error] sbt.internal.io.Retry$.apply(Retry.scala:29)
[error] sbt.internal.io.Retry$.apply(Retry.scala:24)
[error] sbt.internal.server.BspCompileTask$.compute(BspCompileTask.scala:31)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:2319)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:63)
[error] sbt.std.Transform$$anon$4.work(Transform.scala:69)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:283)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:24)
[error] sbt.Execute.work(Execute.scala:292)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:283)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:65)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
[error] java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[error] java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[error] java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[error] java.base/java.lang.Thread.run(Thread.java:1583)
@Katrix Katrix added itype:bug itype:crash stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 2, 2024
@nicolasstucki nicolasstucki added area:metaprogramming:quotes Issues related to quotes and splices and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Mar 4, 2024
@nicolasstucki
Copy link
Contributor

Mimimization

import scala.quoted.*

def test(using Quotes): Any =
  new {
    class IdxWrapper
    def foo(using Type[IdxWrapper]): Expr[Any] = '{ new IdxWrapper }
  }

@nicolasstucki
Copy link
Contributor

[[syntax trees at end of                   staging]] // t/Test.scala
package <empty> {
  import scala.quoted.*
  final lazy module val Test$package: Test$package = new Test$package()
  @SourceFile("t/Test.scala") final module class Test$package() extends Object()
     { this: Test$package.type =>
    private def writeReplace(): AnyRef =
      new scala.runtime.ModuleSerializationProxy(classOf[Test$package.type])
    def test(using x$1: scala.quoted.Quotes): Any =
      {
        final class $anon() extends Object() {
          class IdxWrapper() extends Object() {}
          def foo(using x$1: scala.quoted.Type[IdxWrapper]):
            scala.quoted.Expr[Any] = '<x$1>{new x$1.Underlying()}.apply(x$1)
        }
        new $anon():Object
      }
  }
}

Here '<x$1>{new x$1.Underlying()} the staging phase is trying to heal the reference to the type IdxWrapped inside the new. This will now work for references to local classes.

@nicolasstucki
Copy link
Contributor

-- Error: t/Test.scala:6:32 ----------------------------------------------------
6 |    def foo: Expr[Any] = '{ new IdxWrapper }
  |                                ^^^^^^^^^^
  |Reference to IdxWrapper within quotes requires a given scala.quoted.Type[IdxWrapper] in scope.

This error message is also wrong. It should say that we cannot refer to a local class in a quote.

@Katrix
Copy link
Contributor Author

Katrix commented Mar 4, 2024

Hmm, moving IdxWrapper to a static context I can do fairly easily to work around this, but is there any workarounds for local abstract types?

ElemTop is the thing I am thinking of here, though the bounds on the type type ElemTop <: A and the bounds on X in def indexOf[X <: ElemTop] I get a function that accepts all subtypes of A except A itself. Is there any recommended workarounds for working with abstract types like that in macros without a lof of nasty casting?

(For context, having a value of type Index[A] is unsound)

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Mar 6, 2024
@Kordyjan Kordyjan added this to the 3.4.2 milestone Mar 28, 2024
@Kordyjan Kordyjan modified the milestones: 3.4.2, 3.5.0 May 10, 2024
WojciechMazur pushed a commit that referenced this issue Jul 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants