Skip to content

AssertionError in scalac when compiling a case class with -Ytyper-debug enabled #12675

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

Open
noresttherein opened this issue Oct 26, 2022 · 9 comments
Milestone

Comments

@noresttherein
Copy link

Reproduction steps

Scala version: 2.13.10

case class CaseClass(field :Int)

Problem

When compiling with -Ytyper-debug:

scalac: Error: assertion failed: (CaseClass,case class CaseClass extends scala.Product with scala.Serializable {
  <caseaccessor> <paramaccessor> private[this] val field: Int = _;
  def <init>(field: Int): CaseClass = {
    super.<init>();
    ()
  }
})
java.lang.AssertionError: assertion failed: (CaseClass,case class CaseClass extends scala.Product with scala.Serializable {
  <caseaccessor> <paramaccessor> private[this] val field: Int = _;
  def <init>(field: Int): CaseClass = {
    super.<init>();
    ()
  }
})
	at scala.reflect.internal.SymbolTable.throwAssertionError(SymbolTable.scala:171)
	at scala.tools.nsc.typechecker.TypersTracking$typingStack$.pop(TypersTracking.scala:98)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6100)
	at scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:6125)
	at scala.tools.nsc.typechecker.Typers$Typer.$anonfun$typedStats$8(Typers.scala:3403)
	at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3403)
	at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5640)
	at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5960)
	at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6047)
	at scala.tools.nsc.typechecker.Analyzer$typerFactory$TyperPhase.apply(Analyzer.scala:117)
	at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:467)
	at scala.tools.nsc.typechecker.Analyzer$typerFactory$TyperPhase.run(Analyzer.scala:106)
	at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1530)
	at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1514)
	at scala.tools.nsc.Global$Run.compileSources(Global.scala:1506)
	at scala.tools.nsc.Global$Run.compileFiles(Global.scala:1619)
	at xsbt.CachedCompiler0.run(CompilerBridge.scala:163)
	at xsbt.CachedCompiler0.run(CompilerBridge.scala:134)
	at xsbt.CompilerBridge.run(CompilerBridge.scala:39)
	at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
	at org.jetbrains.jps.incremental.scala.local.IdeaIncrementalCompiler.compile(IdeaIncrementalCompiler.scala:57)
	at org.jetbrains.jps.incremental.scala.local.LocalServer.doCompile(LocalServer.scala:52)
	at org.jetbrains.jps.incremental.scala.local.LocalServer.compile(LocalServer.scala:30)
	at org.jetbrains.jps.incremental.scala.remote.Main$.compileLogic(Main.scala:209)
	at org.jetbrains.jps.incremental.scala.remote.Main$.$anonfun$handleCommand$1(Main.scala:192)
	at org.jetbrains.jps.incremental.scala.remote.Main$.decorated$1(Main.scala:182)
	at org.jetbrains.jps.incremental.scala.remote.Main$.handleCommand(Main.scala:189)
	at org.jetbrains.jps.incremental.scala.remote.Main$.serverLogic(Main.scala:165)
	at org.jetbrains.jps.incremental.scala.remote.Main$.nailMain(Main.scala:105)
	at org.jetbrains.jps.incremental.scala.remote.Main.nailMain(Main.scala)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:578)
	at com.facebook.nailgun.NGSession.runImpl(NGSession.java:312)
	at com.facebook.nailgun.NGSession.run(NGSession.java:198)

Explain how the above behavior isn't what you expected.
Do I have to?

@som-snytt
Copy link

som-snytt commented Oct 26, 2022

Since 2.12.7. -Vtyper in 2.13. It's always been a bit finicky.

Edit: 2.12.7 includes 2.13.0-RC1 backports.

@som-snytt
Copy link

By finicky, I mean duplicates #12601 which is the same stack trace, but I don't remember the disposition, so let's leave this open until there is some clarity.

@noresttherein
Copy link
Author

I don't want to appear entitled, but would it be possible to catch errors in the compiler and provide additional information
about the location in the code it was looking at when it was caught? Stack overflows in the compiler can be super tricky to debug,
it often takes me up to a week to find the cause, especially when introduced by a larger refactor. As the compiler jumps around quite a bit, not always the last location printed by a debug option gives a good idea about where the problem is, let alone what it is.

For example, I personally use something like:

rethrow { persistence.save(entity) } (s"Failed to save $entity.")

def rethrow[T](block: => T)(msg: => String) :T =
  try { block } catch {
    case e :Throwable =>
        e.addSuppressed(new RethrowContext(msg))
        throw e
}
class RethrowContext(msg: =>String) extends Exception {
    override lazy val getMessage = msg
}

It's not a huge effert to pepper the code with such rethrows, at least in places liable to cause problems - TypeComparers would be my first candidate. This way, an exception printed to the console with any standard formatter will include the information from higher on the stack. It really would be a huge quality of life feature from my point of view.

@som-snytt
Copy link

By "larger refactor", I guess you mean that you refactor your code and the (maybe buggy compiler) symptom changes so it's hard to know how to get your code to compile nicely again?

For error context there is https://github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/nsc/Global.scala#L1080

It doesn't always know when to discard error context as it tries a series of adaptations, for example. (Also, not an expert.)

@noresttherein
Copy link
Author

noresttherein commented Oct 27, 2022

I feel really stupid, as I see I actually reported it previously myself and have no recollection of it. I don't know why it didn't show in my search with a stack trace element? I swear I started with it in hope that maybe there is some info on it. I must have searched with the default is:open I guess.

And yes, especially things like adding/removing a type parameter to a whole class hierarchy are risky in my experience.
And regarding the error context, isn't the method only called when the compiler actually reports an error, rather than terminates by throwing an Error?

@som-snytt
Copy link

and have no recollection of it.

That seems totally normal to me. Possibly, I mean "normalized".

I wonder if there are certain refactorings that play havoc with incremental compilation.

I think abort will try to supplement with typer state; it was originally a simpler try-catch thing, IIRC, but I see now it zig-zags through the reporter for the current run (which does all the buffered messaging and warning config).

On context, there have been efforts around typing, but less around crashing cleanly. Maybe Scala 4 will be the compiler with opinionated crashes.

@SethTisue
Copy link
Member

About improving error reporting when the compiler crashes: fwiw, we're trying to improve that in Scala 3 over at scala/scala3#16593 . It's an area where pull requests remain welcome in Scala 2 as well.

@SethTisue SethTisue added this to the Backlog milestone Jan 13, 2023
@SethTisue
Copy link
Member

So, should this one stay open or not? I'm confused by the history here.

@som-snytt
Copy link

The linked ticket had 2 cases: the NPE was transferred to zinc; the assert duplicated this ticket.

I vote leave open for either fix the assertion or improve the crash output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants