Skip to content

Commit 1054624

Browse files
committed
Three fixes wrt handlings of package objects
1. Invalidate packageObj cache when entering a package object 2. Prefer package object members over same-named package members unless we are in the scala package 3. Exclude package objects from no-double-bindings checks, since package objects may now be visited before indexing them.
1 parent 4d76265 commit 1054624

File tree

2 files changed

+68
-28
lines changed

2 files changed

+68
-28
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,9 @@ object SymDenotations {
14931493
myMemberCache
14941494
}
14951495

1496+
/** Hook to do a pre-enter test. Overridden in PackageDenotation */
1497+
protected def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = true
1498+
14961499
/** Enter a symbol in current scope, and future scopes of same denotation.
14971500
* Note: We require that this does not happen after the first time
14981501
* someone does a findMember on a subclass.
@@ -1510,19 +1513,13 @@ object SymDenotations {
15101513
scope
15111514
case _ => unforcedDecls.openForMutations
15121515
}
1513-
if (this is PackageClass) {
1514-
val entry = mscope.lookupEntry(sym.name)
1515-
if (entry != null) {
1516-
if (entry.sym == sym) return
1517-
mscope.unlink(entry)
1518-
entry.sym.denot = sym.denot // to avoid stale symbols
1516+
if (proceedWithEnter(sym, mscope)) {
1517+
enterNoReplace(sym, mscope)
1518+
val nxt = this.nextInRun
1519+
if (nxt.validFor.code > this.validFor.code) {
1520+
this.nextInRun.asSymDenotation.asClass.enter(sym)
15191521
}
15201522
}
1521-
enterNoReplace(sym, mscope)
1522-
val nxt = this.nextInRun
1523-
if (nxt.validFor.code > this.validFor.code) {
1524-
this.nextInRun.asSymDenotation.asClass.enter(sym)
1525-
}
15261523
}
15271524

15281525
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
@@ -1534,7 +1531,7 @@ object SymDenotations {
15341531
(scope ne this.unforcedDecls) ||
15351532
sym.hasAnnotation(defn.ScalaStaticAnnot) ||
15361533
sym.name.isInlineAccessor ||
1537-
isUsecase)
1534+
isUsecase, i"trying to enter $sym in $this, frozen = ${this is Frozen}")
15381535

15391536
scope.enter(sym)
15401537

@@ -1800,7 +1797,7 @@ object SymDenotations {
18001797
/** The denotation of a package class.
18011798
* It overrides ClassDenotation to take account of package objects when looking for members
18021799
*/
1803-
class PackageClassDenotation private[SymDenotations] (
1800+
final class PackageClassDenotation private[SymDenotations] (
18041801
symbol: Symbol,
18051802
ownerIfExists: Symbol,
18061803
name: Name,
@@ -1823,15 +1820,34 @@ object SymDenotations {
18231820
packageObjCache
18241821
}
18251822

1826-
/** Look first for members in package; if none are found look in package object */
1827-
override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation = {
1828-
val denots = super.computeNPMembersNamed(name, inherited)
1829-
if (denots.exists) denots
1830-
else packageObj.moduleClass.denot match {
1831-
case pcls: ClassDenotation => pcls.computeNPMembersNamed(name, inherited)
1832-
case _ => denots
1823+
/** Looks in both the package object and the package for members. The precise algorithm
1824+
* is as follows:
1825+
*
1826+
* If this is the scala package or the package object exists but is currently completing,
1827+
* look in the package first, and if nothing is found there, look in the package object second.
1828+
* Otherwise, look in the package object first, and if nothing is found there, in
1829+
* the package second.
1830+
*
1831+
* The reason for the special treatment of the scala package is that if we
1832+
* complete it too early, we freeze its superclass Any, so that no members can
1833+
* be entered in it. As a consequence, there should be no entry in the scala package
1834+
* object that hides a class or object in the scala package of the same name, because
1835+
* the behavior would then be unintuitive for such members.
1836+
*/
1837+
override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation =
1838+
packageObj.moduleClass.denot match {
1839+
case pcls: ClassDenotation if !pcls.isCompleting =>
1840+
if (symbol eq defn.ScalaPackageClass) {
1841+
val denots = super.computeNPMembersNamed(name, inherited)
1842+
if (denots.exists) denots else pcls.computeNPMembersNamed(name, inherited)
1843+
}
1844+
else {
1845+
val denots = pcls.computeNPMembersNamed(name, inherited)
1846+
if (denots.exists) denots else super.computeNPMembersNamed(name, inherited)
1847+
}
1848+
case _ =>
1849+
super.computeNPMembersNamed(name, inherited)
18331850
}
1834-
}
18351851

18361852
/** The union of the member names of the package and the package object */
18371853
override def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
@@ -1841,6 +1857,21 @@ object SymDenotations {
18411857
case _ => ownNames
18421858
}
18431859
}
1860+
1861+
/** If another symbol with the same name is entered, unlink it,
1862+
* and, if symbol is a package object, invalidate the packageObj cache.
1863+
* @return `sym` is not already entered
1864+
*/
1865+
override def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = {
1866+
val entry = mscope.lookupEntry(sym.name)
1867+
if (entry != null) {
1868+
if (entry.sym == sym) return false
1869+
mscope.unlink(entry)
1870+
entry.sym.denot = sym.denot // to avoid stale symbols
1871+
if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId
1872+
}
1873+
true
1874+
}
18441875
}
18451876

18461877
class NoDenotation extends SymDenotation(

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,20 +1504,29 @@ object Types {
15041504
case _ => NoType
15051505
}
15061506
assert(
1507-
(lastSymbol eq sym) ||
1508-
(lastSymbol eq null) || {
1507+
(lastSymbol eq sym)
1508+
||
1509+
(lastSymbol eq null)
1510+
|| {
15091511
val lastDefRunId = lastDenotation match {
15101512
case d: SymDenotation => d.validFor.runId
15111513
case _ => lastSymbol.defRunId
15121514
}
15131515
(lastDefRunId != sym.defRunId) ||
15141516
(lastDefRunId == NoRunId)
1515-
} ||
1516-
(lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] ||
1517+
}
1518+
||
1519+
lastSymbol.infoOrCompleter.isInstanceOf[ErrorType]
1520+
||
1521+
sym.isPackageObject // package objects can be visited before we get around to index them
1522+
||
15171523
sym.owner != lastSymbol.owner &&
1518-
(sym.owner.derivesFrom(lastSymbol.owner) ||
1519-
selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
1520-
selfTypeOf(lastSymbol).derivesFrom(sym.owner))),
1524+
(sym.owner.derivesFrom(lastSymbol.owner)
1525+
||
1526+
selfTypeOf(sym).derivesFrom(lastSymbol.owner)
1527+
||
1528+
selfTypeOf(lastSymbol).derivesFrom(sym.owner)
1529+
),
15211530
i"""data race? overwriting symbol of type $this,
15221531
|long form = $toString of class $getClass,
15231532
|last sym id = ${lastSymbol.id}, new sym id = ${sym.id},

0 commit comments

Comments
 (0)