Dotty: exception while typing def <init>(): Unit of class class dotty.tools.dotc.ast.Trees$DefDef # 1088

Created on 3 Mar 2020  路  4Comments  路  Source: lampepfl/dotty

minimized code

import java.io.{ OutputStream, PrintStream }

trait Test {
  new PrintStream(new OutputStream {
    def write(b: Int) = ???
  }) {
    override def println(x: Any) = ???
  }
}

Crash output (click arrow to expand)

compile
[info] Compiling 1 Scala source to /Users/thanhbv/ohze/dotty-example/target/scala-0.22/classes ...
exception while typing def <init>(): Unit of class class dotty.tools.dotc.ast.Trees$DefDef # 1088
exception while typing final class $anon() extends java.io.PrintStream($anon$superArg$1()) {
  override def println(x: Any): Unit = ???
  private def $outer: Test
  final def Test$_$$anon$$$outer: Test = $outer
} of class class dotty.tools.dotc.ast.Trees$TypeDef # 1397
exception while typing {
  final class $anon() extends java.io.PrintStream($anon$superArg$1()) {
    override def println(x: Any): Unit = ???
    private def $outer: Test
    final def Test$_$$anon$$$outer: Test = $outer
  }
  private def $anon$superArg$1(): java.io.OutputStream = 
    {
      final class $anon() extends java.io.OutputStream() {
        def write(b: Int): Unit = ???
      }
      new java.io.OutputStream {...}():java.io.OutputStream
    }
  new java.io.PrintStream {...}():java.io.PrintStream
} of class class dotty.tools.dotc.ast.Trees$Block # 1398
exception while typing @scala.annotation.internal.SourceFile(
  "/Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala"
) trait Test() extends Object {
  {
    final class $anon() extends java.io.PrintStream($anon$superArg$1()) {
      override def println(x: Any): Unit = ???
      private def $outer: Test
      final def Test$_$$anon$$$outer: Test = $outer
    }
    private def $anon$superArg$1(): java.io.OutputStream = 
      {
        final class $anon() extends java.io.OutputStream() {
          def write(b: Int): Unit = ???
        }
        new java.io.OutputStream {...}():java.io.OutputStream
      }
    new java.io.PrintStream {...}():java.io.PrintStream
  }
} of class class dotty.tools.dotc.ast.Trees$TypeDef # 1400
exception while typing package <empty> {
  @scala.annotation.internal.SourceFile(
    "/Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala"
  ) trait Test() extends Object {
    {
      final class $anon() extends java.io.PrintStream($anon$superArg$1()) {
        override def println(x: Any): Unit = ???
        private def $outer: Test
        final def Test$_$$anon$$$outer: Test = $outer
      }
      private def $anon$superArg$1(): java.io.OutputStream = 
        {
          final class $anon() extends java.io.OutputStream() {
            def write(b: Int): Unit = ???
          }
          new java.io.OutputStream {...}():java.io.OutputStream
        }
      new java.io.PrintStream {...}():java.io.PrintStream
    }
  }
} of class class dotty.tools.dotc.ast.Trees$PackageDef # 1401
[info] exception occurred while compiling /Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala
scala.MatchError: MethodType(List(), List(), TypeRef(NoPrefix,class $anon)) (of class dotty.tools.dotc.core.Types$CachedMethodType) while compiling /Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala
[error] ## Exception when compiling 1 sources to /Users/thanhbv/ohze/dotty-example/target/scala-0.22/classes
[error] scala.MatchError: MethodType(List(), List(), TypeRef(NoPrefix,class $anon)) (of class dotty.tools.dotc.core.Types$CachedMethodType)
[error] dotty.tools.dotc.transform.ExplicitOuter$OuterOps$.paramDefs$extension(ExplicitOuter.scala:413)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedDefDef(Erasure.scala:615)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2138)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2208)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
[error] dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2247)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2256)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
[error] dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:1801)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2141)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2208)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
[error] dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2247)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2256)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
[error] dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2281)
[error] dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2325)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:747)
[error] dotty.tools.dotc.typer.Typer.typedBlockStats(Typer.scala:796)
[error] dotty.tools.dotc.typer.Typer.typedBlock(Typer.scala:800)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2159)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2209)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
[error] dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2247)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2256)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
[error] dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2303)
[error] dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2325)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:747)
[error] dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:1812)
[error] dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2141)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2208)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
[error] dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2247)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2256)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
[error] dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2281)
[error] dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:2325)
[error] dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:747)
[error] dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:1938)
[error] dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2182)
[error] dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2209)
[error] dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:123)
[error] dotty.tools.dotc.typer.Typer.op$1(Typer.scala:2247)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2256)
[error] dotty.tools.dotc.typer.Typer.typed(Typer.scala:2259)
[error] dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:2367)
[error] dotty.tools.dotc.transform.Erasure.run(Erasure.scala:100)
[error] dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:315)
[error] scala.collection.immutable.List.map(List.scala:219)
[error] dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:316)
[error] dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:167)
[error] dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
[error] dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
[error] scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1323)
[error] dotty.tools.dotc.Run.runPhases$5(Run.scala:177)
[error] dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:185)
[error] dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:64)
[error] dotty.tools.dotc.Run.compileUnits(Run.scala:192)
[error] dotty.tools.dotc.Run.compileSources(Run.scala:129)
[error] dotty.tools.dotc.Run.compile(Run.scala:112)
[error] dotty.tools.dotc.Driver.doCompile(Driver.scala:36)
[error] dotty.tools.dotc.Driver.process(Driver.scala:189)
[error] dotty.tools.dotc.Main.process(Main.scala)
[error] xsbt.CachedCompilerImpl.run(CachedCompilerImpl.java:69)
[error] xsbt.CompilerInterface.run(CompilerInterface.java:41)
[error] sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[error] sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[error] sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[error] java.lang.reflect.Method.invoke(Method.java:498)
[error] sbt.internal.inc.AnalyzingCompiler.call(AnalyzingCompiler.scala:248)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:122)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:95)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:91)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:186)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3(MixedAnalyzingCompiler.scala:82)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$3$adapted(MixedAnalyzingCompiler.scala:77)
[error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:215)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:77)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:146)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:343)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:343)
[error] sbt.internal.inc.Incremental$.doCompile(Incremental.scala:120)
[error] sbt.internal.inc.Incremental$.$anonfun$compile$4(Incremental.scala:100)
[error] sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:180)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:98)
[error] sbt.internal.inc.Incremental$.$anonfun$compile$3(Incremental.scala:102)
[error] sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:155)
[error] sbt.internal.inc.Incremental$.compile(Incremental.scala:92)
[error] sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:75)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:348)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:301)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:168)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:248)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:74)
[error] sbt.Defaults$.compileIncrementalTaskImpl(Defaults.scala:1762)
[error] sbt.Defaults$.$anonfun$compileIncrementalTask$1(Defaults.scala:1735)
[error] scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error] sbt.std.Transform$$anon$4.work(Transform.scala:67)
[error] sbt.Execute.$anonfun$submit$2(Execute.scala:281)
[error] sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:19)
[error] sbt.Execute.work(Execute.scala:290)
[error] sbt.Execute.$anonfun$submit$1(Execute.scala:281)
[error] sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:178)
[error] sbt.CompletionService$$anon$2.call(CompletionService.scala:37)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error] java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[error] java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[error] java.lang.Thread.run(Thread.java:748)
[error]            
[error] stack trace is suppressed; run last Compile / compileIncremental for the full output
[error] (Compile / compileIncremental) scala.MatchError: MethodType(List(), List(), TypeRef(NoPrefix,class $anon)) (of class dotty.tools.dotc.core.Types$CachedMethodType)
[error] Total time: 3 s, completed Mar 3, 2020 7:03:23 PM
[IJ]sbt:dotty-example> 

transform bug crash

All 4 comments

Minimized a bit more:

class Foo(a: Any)

trait Test {
  val x = ""
  val z = new Foo(x) {}
}

(oops no, that one works)

This is a problem with the interaction between ExplicitOuter, Erasure and time-travelling:

  1. In RefChecks#hasJavaErasedOverriding, we run some code with ctx.atPhase(ctx.erasurePhase.next)
  2. This triggers the completion of the denotation transformer for the anonymous class new PrintStream(...), which runs this code: https://github.com/lampepfl/dotty/blob/aea5f3cc5230adabf11ff902e95df2c2035b0bb4/compiler/src/dotty/tools/dotc/core/TypeErasure.scala#L198
  3. OuterOps#addParam in turn relies on ExplicitOuter.hasOuterParam, which lists a very relevant pre-condition: https://github.com/lampepfl/dotty/blob/aea5f3cc5230adabf11ff902e95df2c2035b0bb4/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala#L242-L244
    This is only going to return the correct result after the ExplicitOuter tree transformer has been run (because that's when outer accessors are actually created), but recall that we're inside RefChecks currently, which happens before ExplicitOuter!
  4. The end result is that the denotaiton at phase Erasure we create for the anonymous class constructor is incorrect: it's missing the outer parameter, and this leads to a crash later on.

There's no easy fix here. The only thing I can imagine is that we could disallow forward time-travelling from a phase before ExplicitOuter to a phase at or after Erasure. I think that would only impact the RefEchsk#hasJavaErasedOverriding check which would need to be done later somehow. /cc @odersky

I don't have a fix that could solve all possible races between explicit outer and erasure. But I do have two fixes for this particular problem:

  • we can compensate for missing outer parameters in erasure
  • we can call hasJavaErasedOverriding a lot less often than we do now

Each of these two fixes the problem at hand. #8433 implements both of them.

Was this page helpful?
0 / 5 - 0 ratings