Skip to content

"Missing outer accessor" assertion failure when using plugin with inline #23793

@adkian-sifive

Description

@adkian-sifive

Compiler version

3.3.5, 3.7.2

Explanation

Encountered while migrating the Chisel language to Scala 3. In Chisel, we use plugins to insert typed ASTs to certain user-facing types like Bundles.

In the minimized plugin code below, a plugin is adding a method called _doNothing to all subtypes of Okable. In the test code, we're passing an anonymous Okable subtype by-name to the inline method foo. This construction causes a compiler crash during erasure when the compiler attempts to create a path to _doNothing.

Minimized code

Plugin with Scala-CLI header

plugin.scala

//> using scala "3.7.2" //> using dep "org.scala-lang::scala3-compiler:3.7.2" //> using resourceDir "resources" import dotty.tools.dotc.report import dotty.tools.dotc.plugins.{PluginPhase, StandardPlugin} import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.tpd.Tree import dotty.tools.dotc.ast.tpd.TreeOps import dotty.tools.dotc.CompilationUnit import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.typer.TyperPhase import dotty.tools.dotc.parsing._ import dotty.tools.dotc.core.Names import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Constants.* import dotty.tools.dotc.core.Contexts.* import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.core.Types.* class MyPluginPhase extends PluginPhase { val phaseName: String = "MyPluginPhase" override val runsAfter = Set(TyperPhase.name) def isOkable(t: Type)(using Context): Boolean = { val okableTpe = requiredClass("bug.Okable") t.baseClasses.contains(okableTpe) } def genOkable(outer: tpd.TypeDef)(using ctx: Context): tpd.DefDef = { val newExpr = tpd.New(outer.symbol.typeRef, Nil) val okableTpe = requiredClassRef("bug.Okable") val okableSym = newSymbol( outer.symbol, Names.termName("_makeOkable"), Flags.Method | Flags.Override, MethodType(Nil, Nil, okableTpe) ) tpd.DefDef(okableSym.asTerm, _ => newExpr) } override def transformTypeDef(okable: tpd.TypeDef)(using Context): tpd.Tree = { if (isOkable(okable.tpe) && okable.isClassDef && !okable.symbol.flags.is(Flags.Abstract)) { val thiz: tpd.This = tpd.This(okable.symbol.asClass) val printsOkDef = genOkable(okable) okable match { case td @ tpd.TypeDef(name, tmpl: tpd.Template) => { val newDefs = printsOkDef.toList val newTemplate = if (tmpl.body.size >= 1) cpy.Template(tmpl)(body = newDefs ++: tmpl.body) else cpy.Template(tmpl)(body = newDefs) tpd.cpy.TypeDef(td)(name, newTemplate) } case _ => super.transformTypeDef(okable) } } else { super.transformTypeDef(okable) } } } class MyPlugin extends StandardPlugin { val name: String = "MyPlugin" override val description: String = "MyPlugin" override def init(options: List[String]): List[PluginPhase] = { (new MyPluginPhase) :: Nil } }

Create a resource file with:

mkdir -p resources echo "pluginClass=MyPlugin" > resources/plugin.properties

Package with Scala-CLI:

scala-cli --power package plugin.scala -o plugin.jar --assembly --preamble=false 

Test code:

test.scala

package bug abstract class Okable { def _makeOkable: Okable = ??? } // Plugin adds a _makeOkable override for all Okable abstract class SomeClass extends Okable class SomeChildClass extends SomeClass class Test { inline def foo[A](a: => A): A = a foo { val sc = new SomeClass { val scc = new SomeChildClass } } } 

Compile with (crashes)

scalac -Xplugin:plugin.jar test.scala 

Output (click arrow to expand)

 unhandled exception while running erasure on test.scala An unhandled exception was thrown in the compiler. Please file a crash report here: https://github.com/scala/scala3/issues/new/choose For non-enriched exceptions, compile with -Xno-enrich-error-messages. while compiling: test.scala during phase: erasure mode: Mode(ImplicitsEnabled) library version: version 2.13.15 compiler version: version 3.6.2 settings: -Vprint List(MyPlugin) -Xplugin List(plugin.jar) Exception in thread "main" java.lang.AssertionError: assertion failed: missing outer accessor in class Okable	at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)	at dotty.tools.dotc.transform.ExplicitOuter$.dotty$tools$dotc$transform$ExplicitOuter$$$outerParamAccessor(ExplicitOuter.scala:236)	at dotty.tools.dotc.transform.ExplicitOuter$OuterOps$.loop$1(ExplicitOuter.scala:460)	at dotty.tools.dotc.transform.ExplicitOuter$OuterOps$.path$extension(ExplicitOuter.scala:469)	at dotty.tools.dotc.transform.Erasure$Typer.typedThis(Erasure.scala:814)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3497)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773)	at dotty.tools.dotc.transform.Erasure$Typer.$anonfun$7(Erasure.scala:866)	at dotty.tools.dotc.core.Decorators$.zipWithConserve(Decorators.scala:160)	at dotty.tools.dotc.transform.Erasure$Typer.typedApply(Erasure.scala:866)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3496)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773)	at dotty.tools.dotc.typer.Typer.$anonfun$66(Typer.scala:2897)	at dotty.tools.dotc.inlines.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:256)	at dotty.tools.dotc.typer.Typer.typedDefDef(Typer.scala:2897)	at dotty.tools.dotc.transform.Erasure$Typer.typedDefDef(Erasure.scala:972)	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3478)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:3160)	at dotty.tools.dotc.transform.Erasure$Typer.typedClassDef(Erasure.scala:1061)	at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3484)	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3488)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1427)	at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:1431)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3504)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773)	at dotty.tools.dotc.typer.Typer.typedValDef(Typer.scala:2834)	at dotty.tools.dotc.transform.Erasure$Typer.typedValDef(Erasure.scala:923)	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3475)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1427)	at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:1431)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3504)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773)	at dotty.tools.dotc.typer.Typer.$anonfun$66(Typer.scala:2897)	at dotty.tools.dotc.inlines.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:256)	at dotty.tools.dotc.typer.Typer.typedDefDef(Typer.scala:2897)	at dotty.tools.dotc.transform.Erasure$Typer.typedDefDef(Erasure.scala:972)	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3478)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1427)	at dotty.tools.dotc.typer.ReTyper.typedInlined(ReTyper.scala:99)	at dotty.tools.dotc.transform.Erasure$Typer.typedInlined(Erasure.scala:914)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3519)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3711)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:3160)	at dotty.tools.dotc.transform.Erasure$Typer.typedClassDef(Erasure.scala:1061)	at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3484)	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3488)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3580)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3684)	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3730)	at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1085)	at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:3293)	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3530)	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3581)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3658)	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3662)	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3773)	at dotty.tools.dotc.transform.Erasure.run(Erasure.scala:146)	at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:380)	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:334)	at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:373)	at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:343)	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:336)	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:384)	at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:396)	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69)	at dotty.tools.dotc.Run.compileUnits(Run.scala:396)	at dotty.tools.dotc.Run.compileSources(Run.scala:282)	at dotty.tools.dotc.Run.compile(Run.scala:267)	at dotty.tools.dotc.Driver.doCompile(Driver.scala:37)	at dotty.tools.dotc.Driver.process(Driver.scala:201)	at dotty.tools.dotc.Driver.process(Driver.scala:169)	at dotty.tools.dotc.Driver.process(Driver.scala:181)	at dotty.tools.dotc.Driver.main(Driver.scala:211)	at dotty.tools.MainGenericCompiler$.run$1(MainGenericCompiler.scala:162)	at dotty.tools.MainGenericCompiler$.main(MainGenericCompiler.scala:186)	at dotty.tools.MainGenericCompiler.main(MainGenericCompiler.scala)	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)	at java.base/java.lang.reflect.Method.invoke(Method.java:566)	at coursier.bootstrap.launcher.a.a(Unknown Source)	at coursier.bootstrap.launcher.Launcher.main(Unknown Source)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions