Scala 3 macros: compiler fails with `NoSuchElementException: key not found: class $anon`

Hello there!

Honestly, I cannot give a reproducer for this yet. At least, a short and concise reproducer. This error happens inside of rather large and bulky macro code, and I’m not sure what is triggering it. So far, all my attempts to make some minimal sample just made the error disappear.

Context: there is a library which derives an implementation of type class (producing anonymous classes). During this derivation, it may also derive impls for dependent types, thus producing multiple anonymous classes at same level. Classes are combined like that:

// Somewhere:
class ClassWrapper[X] extends TypeClass[X] { 
  private var _impl: TypeClass[X] = _
  def set(x: TypeClass[X]): Unit = _impl = x
  def foo(value: X): Unit = _impl.foo()
}

val r: TypeClass[T2] = /* macro expansion */ {
  val r1: ClassWrapper[T1] = new ClassWrapper[T1]
  val r2: ClassWrapper[T2] = new ClassWrapper[T2]
  r1.set(new TypeClass[T1] {
    def foo(value: T1): Unit = { /* ... */ }
  })
  r2.set(new TypeClass[T2] {
    def foo(value: T2): Unit = { /* ... use r1 ... */ }
  })
  r2
}

Error happens only if two of such classes are produced in same macro expansion.

So, I’m looking for some guidance on what it could be. Since Scala 3 quotes and splices are far less powerful than Scala 2 quasiquotes, I have to construct some AST by hand. And it’s possible that I’m messed up with symbol ownership somewhere. Also I’m ocassionally casting some Symbols and TypeReprs between different Quotes universes (i.e. sym1.asInstanceOf[q2.reflect.Symbol]), but these universes are belonging to same macro expansion. Other than that, I don’t see any parts that looks like being unsafe.

I could provide source code for library itself (it will go opensource anyway after being finished), but I’m doubt that someone is going to debug tons of code.

Scala version: 3.2.0, 3.2.2-RC1-bin-20220927-731522a-NIGHTLY (stack trace is from nightly version)
Stack trace:

[error] java.util.NoSuchElementException: key not found: class $anon
[error] scala.collection.MapOps.default(Map.scala:274)
[error] scala.collection.MapOps.default$(Map.scala:273)
[error] scala.collection.AbstractMap.default(Map.scala:405)
[error] scala.collection.MapOps.apply(Map.scala:176)
[error] scala.collection.MapOps.apply$(Map.scala:175)
[error] scala.collection.AbstractMap.apply(Map.scala:405)
[error] dotty.tools.dotc.transform.Dependencies.narrowLogicOwner(Dependencies.scala:82)
[error] dotty.tools.dotc.transform.Dependencies.markFree(Dependencies.scala:148)
[error] dotty.tools.dotc.transform.Dependencies.markFree(Dependencies.scala:146)
[error] dotty.tools.dotc.transform.Dependencies.process(Dependencies.scala:210)
[error] dotty.tools.dotc.transform.LambdaLift$Lifter$$anon$1.process(LambdaLift.scala:41)
[error] dotty.tools.dotc.transform.LambdaLift$Lifter$$anon$1.process(LambdaLift.scala:40)
[error] dotty.tools.dotc.transform.Dependencies$CollectDependencies.traverse(Dependencies.scala:240)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1657)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1657)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1529)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1531)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1548)
[error] dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1658)
[error] dotty.tools.dotc.transform.Dependencies$CollectDependencies.traverse(Dependencies.scala:241)
// < trace continued with repeating CollectDependencies.traverse blocks >
1 Like

Eventually turned out to be a compiler bug: