Skip to content

Inlining of references to private members in nested anonymous classes generates missing inline access proxies #26178

Description

@starswap

Compiler version

3.8.3, also fails on latest main.

Minimized code

class C:
  private def secret = 42
  def foo = 10
  inline def m = new C { override def foo = secret }

@main def main =
  val e = new C().m
  println(s"The secret is ${e.foo}")

Output

At compile time an unrelated warning (New anonymous class definition will be duplicated at each inline site).
At runtime:

Exception in thread "main" java.lang.NoSuchMethodError: 'int private$minusinline$minussubclass$package$$anon$1.inline$secret()'
        at private$minusinline$minussubclass$package$$anon$1.foo(private-inline-subclass.scala:6)
        at private$minusinline$minussubclass$package$.main(private-inline-subclass.scala:10)
        at main.main(private-inline-subclass.scala:8)

Under -Ycheck:all this aborts on the missing access proxy:

checking tests/run/private-inline-subclass.scala after phase typer
*** error while checking tests/run/private-inline-subclass.scala after phase typer ***

  unhandled exception while running Ycheck on tests/run/private-inline-subclass.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: tests/run/private-inline-subclass.scala
        during phase: Ycheck
                mode: Mode(ImplicitsEnabled)
     library version: version 3.8.3
    compiler version: version 3.8.3
            settings: -Vprint List(all) -Ycheck List(all)

Exception in thread "main" java.lang.AssertionError: assertion failed: anonymous class C {...} tree does not define members: method inline$secret
expected: constructor $anon, method foo, method inline$secret
defined: method foo
        at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:10)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedClassDef(TreeChecker.scala:616)
        at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3791)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3795)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3896)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:4011)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:4058)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:691)
        at dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:1537)
        at dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:1541)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedBlock$$anonfun$1$$anonfun$1(TreeChecker.scala:673)
        at dotty.tools.dotc.transform.TreeChecker$Checker.withDefinedSyms(TreeChecker.scala:278)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedBlock$$anonfun$1(TreeChecker.scala:673)
        at dotty.tools.dotc.transform.TreeChecker$Checker.withBlock(TreeChecker.scala:306)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedBlock(TreeChecker.scala:673)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3811)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3897)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedTyped(TreeChecker.scala:566)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3808)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3897)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:4101)
        at dotty.tools.dotc.typer.Typer.$anonfun$69(Typer.scala:3141)
        at dotty.tools.dotc.inlines.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:256)
        at dotty.tools.dotc.typer.Typer.typedDefDef(Typer.scala:3141)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedDefDef$$anonfun$1(TreeChecker.scala:648)
        at dotty.tools.dotc.transform.TreeChecker$Checker.withDefinedSyms(TreeChecker.scala:278)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedDefDef(TreeChecker.scala:651)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3785)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3896)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:4011)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:4058)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:691)
        at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:3449)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedClassDef(TreeChecker.scala:618)
        at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3791)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3795)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3896)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:4011)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:4058)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:691)
        at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:3584)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3837)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3897)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:434)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3984)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3989)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:417)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:4101)
        at dotty.tools.dotc.transform.TreeChecker.check(TreeChecker.scala:131)
        at dotty.tools.dotc.transform.TreeChecker.run(TreeChecker.scala:111)
        at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:406)
        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:327)
        at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:399)
        at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:380)
        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:1324)
        at dotty.tools.dotc.Run.runPhases$1(Run.scala:373)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1$$anonfun$2(Run.scala:420)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1$$anonfun$adapted$1(Run.scala:420)
        at scala.Function0.apply$mcV$sp(Function0.scala:42)
        at dotty.tools.dotc.Run.showProgress(Run.scala:482)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:420)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:432)
        at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:69)
        at dotty.tools.dotc.Run.compileUnits(Run.scala:432)
        at dotty.tools.dotc.Run.compileSources(Run.scala:319)
        at dotty.tools.dotc.Run.compile(Run.scala:304)
        at dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
        at dotty.tools.dotc.Driver.process(Driver.scala:212)
        at dotty.tools.dotc.Driver.process(Driver.scala:180)
        at dotty.tools.dotc.Driver.process(Driver.scala:192)
        at dotty.tools.dotc.Driver.main(Driver.scala:222)
        at dotty.tools.MainGenericCompiler$.main(MainGenericCompiler.scala:122)
        at dotty.tools.MainGenericCompiler.main(MainGenericCompiler.scala)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at coursier.bootstrap.launcher.a.a(Unknown Source)
        at coursier.bootstrap.launcher.Launcher.main(Unknown Source)

Expectation

The secret is 42.

Or otherwise a compiler error if we don't think this should inline.

Ran into this while working on my specialized traits work (#26156), as we are using anonymous class instances to instantiate the specialized traits, but this turns out not to be specific to specialized or inline traits. I'll try and find a fix as I could do with this for my examples for specialized traits. Ideally we can make it inline correctly by putting the proxy somewhere sensible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    itype:bugstat:needs triageEvery issue needs to have an "area" and "itype" label

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions