Skip to content

Commit 225ede6

Browse files
committed
Avoid referring to stale package object member symbols
1 parent b911c22 commit 225ede6

File tree

8 files changed

+49
-19
lines changed

8 files changed

+49
-19
lines changed

src/compiler/scala/tools/nsc/Global.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
390390

391391
// ------------ Phases -------------------------------------------}
392392

393-
var globalPhase: Phase = NoPhase
393+
private[this] var _globalPhase: Phase = NoPhase
394+
override final def globalPhase: Phase = _globalPhase
395+
final def globalPhase_=(ph: Phase): Unit = _globalPhase = ph
394396

395397
abstract class GlobalPhase(prev: Phase) extends Phase(prev) {
396398
phaseWithId(id) = this

src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,13 @@ abstract class SymbolLoaders {
4747
protected def compileLate(srcfile: AbstractFile): Unit
4848

4949
protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
50-
assert(owner.info.decls.lookup(member.name) == NoSymbol, owner.fullName + "." + member.name)
51-
owner.info.decls enter member
52-
member
50+
owner.info.decls.lookup(member.name) match {
51+
case NoSymbol =>
52+
owner.info.decls enter member
53+
member
54+
case member =>
55+
member
56+
}
5357
}
5458

5559
protected def signalError(root: Symbol, ex: Throwable) {
@@ -280,10 +284,11 @@ abstract class SymbolLoaders {
280284
val shownPackageName = if (packageName == ClassPath.RootPackage) "<root package>" else packageName
281285
s"package loader $shownPackageName"
282286
}
287+
override val decls = newScope
283288

284289
protected def doComplete(root: Symbol) {
285290
assert(root.isPackageClass, root)
286-
root.setInfo(new PackageClassInfoType(newScope, root))
291+
root.setInfo(new PackageClassInfoType(decls, root))
287292

288293
val classPathEntries = classPath.list(packageName)
289294

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,8 @@ trait Namers extends MethodSynthesis {
762762
def enterPackage(tree: PackageDef) {
763763
val sym = createPackageSymbol(tree.pos, tree.pid)
764764
tree.symbol = sym
765-
newNamer(context.make(tree, sym.moduleClass, sym.info.decls)) enterSyms tree.stats
765+
val scope = sym.rawInfo.typeSymbolDirect.rawInfo.decls
766+
newNamer(context.make(tree, sym.moduleClass, scope)) enterSyms tree.stats
766767
}
767768

768769
private def enterImport(tree: Import) = {
@@ -2161,7 +2162,7 @@ trait Namers extends MethodSynthesis {
21612162
// scala/bug#7264 Force the info of owners from previous compilation runs.
21622163
// Doing this generally would trigger cycles; that's what we also
21632164
// use the lower-level scan through the current Context as a fall back.
2164-
if (!currentRun.compiles(owner)) owner.initialize
2165+
if (!owner.isPackageClass && !currentRun.compiles(owner)) owner.initialize
21652166

21662167
if (original.isModuleClass) original.sourceModule
21672168
else if (!owner.isTerm && owner.hasCompleteInfo)

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,9 +1863,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
18631863
def typedModuleDef(mdef: ModuleDef): Tree = {
18641864
// initialize all constructors of the linked class: the type completer (Namer.methodSig)
18651865
// might add default getters to this object. example: "object T; class T(x: Int = 1)"
1866-
val linkedClass = companionSymbolOf(mdef.symbol, context)
1867-
if (linkedClass != NoSymbol)
1866+
val linkedClass = companionSymbolOf(mdef.symbol, context).suchThat { sym =>
1867+
val isStale = sym.rawInfo.isInstanceOf[loaders.ClassfileLoader]
1868+
if (isStale) sym.owner.info.decls.unlink(sym)
1869+
!isStale
1870+
}
1871+
if (linkedClass != NoSymbol) {
18681872
linkedClass.info.decl(nme.CONSTRUCTOR).alternatives foreach (_.initialize)
1873+
}
18691874

18701875
val clazz = mdef.symbol.moduleClass
18711876
currentRun.profiler.beforeTypedImplDef(clazz)

src/reflect/scala/reflect/internal/SymbolTable.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ abstract class SymbolTable extends macros.Universe
244244
final def phase: Phase = {
245245
ph
246246
}
247+
def globalPhase: Phase = phase
247248

248249
def atPhaseStackMessage = atPhaseStack match {
249250
case Nil => ""
@@ -352,6 +353,7 @@ abstract class SymbolTable extends macros.Universe
352353

353354
def openPackageModule(container: Symbol, dest: Symbol) {
354355
// unlink existing symbols in the package
356+
assert(globalPhase.name != "namer")
355357
for (member <- container.info.decls.iterator) {
356358
if (!member.isPrivate && !member.isConstructor) {
357359
// todo: handle overlapping definitions in some way: mark as errors

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3541,7 +3541,7 @@ trait Types
35413541
// Creators ---------------------------------------------------------------
35423542

35433543
/** Rebind symbol `sym` to an overriding member in type `pre`. */
3544-
private def rebind(pre: Type, sym: Symbol): Symbol = {
3544+
private[scala] def rebind(pre: Type, sym: Symbol): Symbol = {
35453545
if (!sym.isOverridableMember || sym.owner == pre.typeSymbol) sym
35463546
else pre.nonPrivateMember(sym.name).suchThat { sym =>
35473547
// scala/bug#7928 `isModuleNotMethod` is here to avoid crashing with spuriously "overloaded" module accessor and module symbols.

test/junit/scala/tools/nsc/DeterminismTest.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package scala.tools.nsc
22

3-
import org.junit.Test
3+
import java.nio.file.{Files, Path, Paths}
4+
5+
import org.junit.{Ignore, Test}
46

57
import scala.reflect.internal.util.{BatchSourceFile, SourceFile}
8+
import scala.reflect.io.AbstractFile
69

710
class DeterminismTest {
811
private val tester = new DeterminismTester
@@ -309,5 +312,14 @@ class DeterminismTest {
309312
test(List(code))
310313
}
311314

315+
@Test def testPackageObjectUserLand(): Unit = {
316+
def code = List[SourceFile](
317+
source("package.scala", "package userland; object `package` { type Throwy = java.lang.Throwable }"),
318+
source("th.scala", "package userland; class th[T <: Throwy](cause: T = null)")
319+
)
320+
test(code :: Nil, permuter = _.reverse :: Nil)
321+
}
322+
312323
def source(name: String, code: String): SourceFile = new BatchSourceFile(name, code)
324+
def source(path: Path): SourceFile = new BatchSourceFile(AbstractFile.getFile(path.toFile))
313325
}

test/junit/scala/tools/nsc/DeterminismTester.scala

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,19 @@ object DeterminismTester extends DeterminismTester {
3131
else path :: Nil
3232
}
3333
val sourceFiles = sourceFilesPaths.map(Paths.get(_)).flatMap(expand).map(path => new BatchSourceFile(AbstractFile.getFile(path.toFile)))
34-
test(scalacOpts, sourceFiles :: Nil)
34+
test(sourceFiles :: Nil, scalacOpts)
3535
}
3636
}
3737

3838
class DeterminismTester {
3939

40-
def test(groups: List[List[SourceFile]]): Unit = test(Nil, groups)
41-
def test(scalacOptions: List[String], groups: List[List[SourceFile]]): Unit = {
40+
def test(groups: List[List[SourceFile]]): Unit = test(groups, Nil)
41+
def test(groups: List[List[SourceFile]], scalacOptions: List[String] = Nil,
42+
permuter: List[SourceFile] => List[List[SourceFile]] = defaultPermuter(_)): Unit = {
4243
val referenceOutput = Files.createTempDirectory("reference")
4344

4445
def compile(output: Path, files: List[SourceFile]): Unit = {
45-
// println("compile: " + files)
46+
println("====== compile: " + files.map(_.file.absolute).map("\"" + _ + "\"").mkString(",\n"))
4647
val g = new Global(new Settings)
4748
g.settings.usejavacp.value = true
4849
g.settings.classpath.value = output.toAbsolutePath.toString
@@ -88,9 +89,7 @@ class DeterminismTester {
8889
super.visitFile(file, attrs)
8990
}
9091
}
91-
val permutations: List[List[SourceFile]] = if (groups.last.size > 32) {
92-
groups.last.reverse :: groups.last.map(_ :: Nil)
93-
} else permutationsWithSubsets(groups.last)
92+
val permutations: List[List[SourceFile]] = permuter(groups.last)
9493
for (permutation <- permutations) {
9594
val recompileOutput = Files.createTempDirectory("recompileOutput")
9695
copyRecursive(referenceOutput, recompileOutput)
@@ -99,7 +98,11 @@ class DeterminismTester {
9998
deleteRecursive(recompileOutput)
10099
}
101100
deleteRecursive(referenceOutput)
102-
101+
}
102+
def defaultPermuter(sources: List[SourceFile]): List[List[SourceFile]] = {
103+
if (sources.size > 32) {
104+
sources.reverse :: sources.map(_ :: Nil)
105+
} else permutationsWithSubsets(sources)
103106
}
104107
def permutationsWithSubsets[A](as: List[A]): List[List[A]] =
105108
as.permutations.toList.flatMap(_.inits.filter(_.nonEmpty)).distinct

0 commit comments

Comments
 (0)