Skip to content

Commit 77b247d

Browse files
committed
Fix #2809: Invalidate and unlink symbols for artifact classfiles
This is similar to scala/scala#5952, we do not need to parse artifact classfiles (that is, classfiles produced by scalac or dotty that do not contain pickling information), so we discard them as soon as possible. This fixes various IDE crashes when trying to complete packages such as "scala."
1 parent 1816a19 commit 77b247d

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import scala.util.control.NonFatal
1919
object ClassfileParser {
2020
/** Marker trait for unpicklers that can be embedded in classfiles. */
2121
trait Embedded
22+
23+
/** Indicate that there is nothing to unpickle and the corresponding symbols can
24+
* be invalidated. */
25+
object NoEmbedded extends Embedded
2226
}
2327

2428
class ClassfileParser(
@@ -147,6 +151,15 @@ class ClassfileParser(
147151

148152
setClassInfo(classRoot, classInfo)
149153
setClassInfo(moduleRoot, staticInfo)
154+
} else if (result == Some(NoEmbedded)) {
155+
for (sym <- List(moduleRoot.sourceModule.symbol, moduleRoot.symbol, classRoot.symbol)) {
156+
classRoot.owner.asClass.delete(sym)
157+
if (classRoot.owner == defn.ScalaShadowingPackageClass) {
158+
// Symbols in scalaShadowing are also added to scala
159+
defn.ScalaPackageClass.delete(sym)
160+
}
161+
sym.markAbsent()
162+
}
150163
}
151164

152165
// eager load java enum definitions for exhaustivity check of pattern match
@@ -700,6 +713,10 @@ class ClassfileParser(
700713
}
701714
}
702715

716+
// Nothing$ and Null$ were incorrectly emitted with a Scala attribute
717+
// instead of ScalaSignature before 2.13.0-M2, see https://github.com/scala/scala/pull/5952
718+
private[this] val scalaUnpickleWhitelist = List(tpnme.nothingClass, tpnme.nullClass)
719+
703720
/** Parse inner classes. Expects `in.bp` to point to the superclass entry.
704721
* Restores the old `bp`.
705722
* @return true iff classfile is from Scala, so no Java info needs to be read.
@@ -760,6 +777,18 @@ class ClassfileParser(
760777
return unpickleTASTY(in.nextBytes(attrLen))
761778
}
762779

780+
if (scan(tpnme.ScalaATTR) && !scalaUnpickleWhitelist.contains(classRoot.name)) {
781+
// To understand the situation, it's helpful to know that:
782+
// - Scalac emits the `ScalaSig` attribute for classfiles with pickled information
783+
// and the `Scala` attribute for everything else.
784+
// - Dotty emits the `TASTY` attribute for classfiles with pickled information
785+
// and the `Scala` attribute for _every_ classfile.
786+
//
787+
// Therefore, if the `Scala` attribute is present but the `TASTY`
788+
// attribute isn't, this classfile is a compilation artifact.
789+
return Some(NoEmbedded)
790+
}
791+
763792
if (scan(tpnme.RuntimeAnnotationATTR)) {
764793
val attrLen = in.nextInt
765794
val nAnnots = in.nextChar

tests/neg/classfile-artifacts.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// For some reason, if the imports are not scoped, only the first import error
2+
// is reported
3+
4+
class A {
5+
import scala.languageFeature$experimental$._ // error
6+
}
7+
8+
class B {
9+
import scala.language$Scala2$._ // error
10+
}
11+
12+
class C {
13+
import scala.languageFeature$._ // error
14+
}
15+

0 commit comments

Comments
 (0)