-
Notifications
You must be signed in to change notification settings - Fork 21
Open
Milestone
Description
Reproduction steps
Scala version: 2.13.16
Using Metals, trying to enable errors as you type (scalameta/metals#7430)
case class Foo(name: String = "")
object Foo extends Foo("")
Problem
The presentation compiler crashes trying to find default getters in the companion object and failing to do so. This only happens when:
- there are default arguments
- the object definition is after the class definition
In my investigations I could find that the trigger is that the presentation compiler tries to call invalidateCaches on the previous Run's symbol, which calls into baseClasses
, which forces the old symbol before the ConstructorDefaultsAttachment
is attached to the class symbol.
Presentation compiler test:
diff --git forkSrcPrefix/test/files/presentation/case-class-default-params/Test.scala forkDstPrefix/test/files/presentation/case-class-default-params/Test.scala
new file mode 100644
index 0000000000000000000000000000000000000000..f91dc1090ed484a4b9fdda437f0ef736de18ad1a
--- /dev/null
+++ forkDstPrefix/test/files/presentation/case-class-default-params/Test.scala
@@ -0,0 +1,34 @@
+import scala.tools.nsc.interactive.tests.InteractiveTest
+import scala.reflect.internal.util.SourceFile
+import scala.tools.nsc.interactive.Response
+
+object Test extends InteractiveTest {
+ override def execute(): Unit = {
+ val source = loadSourceAndWaitUntilTypechecked("Foo.scala")
+ checkErrors(source)
+ }
+
+ private def loadSourceAndWaitUntilTypechecked(sourceName: String): SourceFile = {
+ val sourceFile = sourceFiles.find(_.file.name == sourceName).get
+ compiler.askToDoFirst(sourceFile)
+ val res = new Response[Unit]
+ compiler.askReload(List(sourceFile), res)
+ res.get
+ askLoadedTyped(sourceFile).get
+ // the second round of type-checking makes it fail
+ compiler.askReload(List(sourceFile), res)
+ res.get
+ askLoadedTyped(sourceFile).get
+
+ sourceFile
+ }
+
+ private def checkErrors(source: SourceFile): Unit = compiler.getUnitOf(source) match {
+ case Some(unit) =>
+ val problems = unit.problems.toList
+ if(problems.isEmpty) reporter.println("Test OK")
+ else problems.foreach(problem => reporter.println(problem.msg))
+
+ case None => reporter.println("No compilation unit found for " + source.file.name)
+ }
+}
diff --git forkSrcPrefix/test/files/presentation/case-class-default-params/src/Foo.scala forkDstPrefix/test/files/presentation/case-class-default-params/src/Foo.scala
new file mode 100644
index 0000000000000000000000000000000000000000..ee1e97716fd4b67101a63f25b427a430cb9f3c4c
--- /dev/null
+++ forkDstPrefix/test/files/presentation/case-class-default-params/src/Foo.scala
@@ -0,0 +1,2 @@
+case class Foo(name: String = "")
+object Foo extends Foo("")
Stack trace:
[Foo.scala]: exception during background compile: java.lang.AssertionError: assertion failed:
(object Foo,$lessinit$greater$default$1)
while compiling: case-class-default-params/src/Foo.scala
during phase: globalPhase=<no phase>, enteringPhase=namer
library version: version 2.13.16-20250107-233423-3f6bdae
compiler version: version 2.13.16-20250107-233423-3f6bdae
reconstructed args: -usejavacp -Ymacro-expand:discard
last tree to typer: Ident(Foo)
tree position: line 2 of case-class-default-params/src/Foo.scala
tree tpe: Foo
symbol: case class Foo
symbol definition: case class Foo extends Product with Serializable (a ClassSymbol)
symbol package: <empty>
symbol owners: class Foo
call site: <none> in <none>
== Source file context for tree position ==
1 case class Foo(name: String = "")
2 object Foo extends Foo("")
3
java.lang.AssertionError: assertion failed:
(object Foo,$lessinit$greater$default$1)
while compiling: case-class-default-params/src/Foo.scala
during phase: globalPhase=<no phase>, enteringPhase=namer
library version: version 2.13.16-20250107-233423-3f6bdae
compiler version: version 2.13.16-20250107-233423-3f6bdae
reconstructed args: -usejavacp -Ymacro-expand:discard
last tree to typer: Ident(Foo)
tree position: line 2 of case-class-default-params/src/Foo.scala
tree tpe: Foo
symbol: case class Foo
symbol definition: case class Foo extends Product with Serializable (a ClassSymbol)
symbol package: <empty>
symbol owners: class Foo
call site: <none> in <none>
== Source file context for tree position ==
1 case class Foo(name: String = "")
2 object Foo extends Foo("")
3
at scala.reflect.internal.SymbolTable.throwAssertionError(SymbolTable.scala:173)
at scala.reflect.internal.SymbolTable.assert(SymbolTable.scala:159)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$addDefaultGetters$10(Namers.scala:1616)
at scala.tools.nsc.typechecker.Namers$Namer$DefaultGetterInCompanion.addGetter(Namers.scala:1673)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$addDefaultGetters$8(Namers.scala:1586)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$addDefaultGetters$8$adapted(Namers.scala:1557)
at scala.reflect.internal.util.Collections.foreach2(Collections.scala:260)
at scala.reflect.internal.util.Collections.foreach2$(Collections.scala:256)
at scala.reflect.internal.SymbolTable.foreach2(SymbolTable.scala:28)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$addDefaultGetters$6(Namers.scala:1557)
at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:183)
at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:179)
at scala.collection.immutable.List.foldLeft(List.scala:79)
at scala.tools.nsc.typechecker.Namers$Namer.addDefaultGetters(Namers.scala:1553)
at scala.tools.nsc.typechecker.Namers$Namer.methodSig(Namers.scala:1426)
at scala.tools.nsc.typechecker.Namers$Namer.memberSig(Namers.scala:1929)
at scala.tools.nsc.typechecker.Namers$Namer.typeSig(Namers.scala:1880)
at scala.tools.nsc.typechecker.Namers$Namer$MonoTypeCompleter.completeImpl(Namers.scala:834)
at scala.tools.nsc.typechecker.Namers$LockingTypeCompleter.complete(Namers.scala:2077)
at scala.tools.nsc.typechecker.Namers$LockingTypeCompleter.complete$(Namers.scala:2075)
at scala.tools.nsc.typechecker.Namers$TypeCompleterBase.complete(Namers.scala:2070)
at scala.reflect.internal.Symbols$Symbol.completeInfo(Symbols.scala:1583)
at scala.reflect.internal.Symbols$Symbol.info(Symbols.scala:1548)
at scala.reflect.internal.Symbols$Symbol.initialize(Symbols.scala:1747)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5916)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6344)
at scala.tools.nsc.typechecker.Typers$Typer.typedByValueExpr(Typers.scala:6422)
at scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:3387)
at scala.tools.nsc.typechecker.Typers$Typer.$anonfun$typedStats$10(Typers.scala:3547)
at scala.collection.immutable.List.loop$3(List.scala:473)
at scala.collection.immutable.List.mapConserve(List.scala:498)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3547)
at scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:2133)
at scala.tools.nsc.typechecker.Typers$Typer.typedClassDef(Typers.scala:1971)
at scala.tools.nsc.typechecker.Typers$Typer.typedMemberDef$1(Typers.scala:6251)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:6304)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6344)
at scala.tools.nsc.typechecker.Typers$Typer.typedByValueExpr(Typers.scala:6422)
at scala.tools.nsc.typechecker.Typers$Typer.typedStat$1(Typers.scala:3387)
at scala.tools.nsc.typechecker.Typers$Typer.$anonfun$typedStats$10(Typers.scala:3547)
at scala.collection.immutable.List.loop$3(List.scala:473)
at scala.collection.immutable.List.mapConserve(List.scala:498)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3547)
at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5925)
at scala.tools.nsc.typechecker.Typers$Typer.typedMemberDef$1(Typers.scala:6254)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:6304)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6344)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:6420)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$TyperPhase.apply(Analyzer.scala:126)
at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:483)
at scala.tools.nsc.interactive.Global$TyperRun.$anonfun$applyPhase$1(Global.scala:1370)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at scala.reflect.internal.SymbolTable.enteringPhase(SymbolTable.scala:292)
at scala.tools.nsc.interactive.Global$TyperRun.applyPhase(Global.scala:1370)
at scala.tools.nsc.interactive.Global$TyperRun.typeCheck(Global.scala:1363)
at scala.tools.nsc.interactive.Global.typeCheck(Global.scala:681)
at scala.tools.nsc.interactive.Global.$anonfun$backgroundCompile$7(Global.scala:591)
at scala.tools.nsc.interactive.Global.$anonfun$backgroundCompile$7$adapted(Global.scala:587)
at scala.Option.foreach(Option.scala:437)
at scala.tools.nsc.interactive.Global.$anonfun$backgroundCompile$6(Global.scala:587)
at scala.tools.nsc.interactive.Global.$anonfun$backgroundCompile$6$adapted(Global.scala:587)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:619)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:617)
at scala.collection.AbstractIterable.foreach(Iterable.scala:935)
at scala.collection.IterableOps$WithFilter.foreach(Iterable.scala:905)
at scala.tools.nsc.interactive.Global.backgroundCompile(Global.scala:587)
at scala.tools.nsc.interactive.PresentationCompilerThread.run(PresentationCompilerThread.scala:32)