aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/core/SymDenotations.scala72
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeComparer.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala23
-rw-r--r--tests/pos/i2200/Hello.scala6
-rw-r--r--tests/pos/i2200/package.scala4
5 files changed, 80 insertions, 32 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index 602848a50..6d1a006ed 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1493,6 +1493,9 @@ object SymDenotations {
myMemberCache
}
+ /** Hook to do a pre-enter test. Overridden in PackageDenotation */
+ protected def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = true
+
/** Enter a symbol in current scope, and future scopes of same denotation.
* Note: We require that this does not happen after the first time
* someone does a findMember on a subclass.
@@ -1510,19 +1513,13 @@ object SymDenotations {
scope
case _ => unforcedDecls.openForMutations
}
- if (this is PackageClass) {
- val entry = mscope.lookupEntry(sym.name)
- if (entry != null) {
- if (entry.sym == sym) return
- mscope.unlink(entry)
- entry.sym.denot = sym.denot // to avoid stale symbols
+ if (proceedWithEnter(sym, mscope)) {
+ enterNoReplace(sym, mscope)
+ val nxt = this.nextInRun
+ if (nxt.validFor.code > this.validFor.code) {
+ this.nextInRun.asSymDenotation.asClass.enter(sym)
}
}
- enterNoReplace(sym, mscope)
- val nxt = this.nextInRun
- if (nxt.validFor.code > this.validFor.code) {
- this.nextInRun.asSymDenotation.asClass.enter(sym)
- }
}
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
@@ -1534,7 +1531,7 @@ object SymDenotations {
(scope ne this.unforcedDecls) ||
sym.hasAnnotation(defn.ScalaStaticAnnot) ||
sym.name.isInlineAccessor ||
- isUsecase)
+ isUsecase, i"trying to enter $sym in $this, frozen = ${this is Frozen}")
scope.enter(sym)
@@ -1800,7 +1797,7 @@ object SymDenotations {
/** The denotation of a package class.
* It overrides ClassDenotation to take account of package objects when looking for members
*/
- class PackageClassDenotation private[SymDenotations] (
+ final class PackageClassDenotation private[SymDenotations] (
symbol: Symbol,
ownerIfExists: Symbol,
name: Name,
@@ -1823,15 +1820,33 @@ object SymDenotations {
packageObjCache
}
- /** Look first for members in package; if none are found look in package object */
- override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation = {
- val denots = super.computeNPMembersNamed(name, inherited)
- if (denots.exists) denots
- else packageObj.moduleClass.denot match {
- case pcls: ClassDenotation => pcls.computeNPMembersNamed(name, inherited)
- case _ => denots
+ /** Looks in both the package object and the package for members. The precise algorithm
+ * is as follows:
+ *
+ * If this is the scala package look in the package first, and if nothing is found
+ * there, look in the package object second. Otherwise, look in the package object
+ * first, and if nothing is found there, in the package second.
+ *
+ * The reason for the special treatment of the scala package is that if we
+ * complete it too early, we freeze its superclass Any, so that no members can
+ * be entered in it. As a consequence, there should be no entry in the scala package
+ * object that hides a class or object in the scala package of the same name, because
+ * the behavior would then be unintuitive for such members.
+ */
+ override def computeNPMembersNamed(name: Name, inherited: Boolean)(implicit ctx: Context): PreDenotation =
+ packageObj.moduleClass.denot match {
+ case pcls: ClassDenotation if !pcls.isCompleting =>
+ if (symbol eq defn.ScalaPackageClass) {
+ val denots = super.computeNPMembersNamed(name, inherited)
+ if (denots.exists) denots else pcls.computeNPMembersNamed(name, inherited)
+ }
+ else {
+ val denots = pcls.computeNPMembersNamed(name, inherited)
+ if (denots.exists) denots else super.computeNPMembersNamed(name, inherited)
+ }
+ case _ =>
+ super.computeNPMembersNamed(name, inherited)
}
- }
/** The union of the member names of the package and the package object */
override def memberNames(keepOnly: NameFilter)(implicit ctx: Context): Set[Name] = {
@@ -1841,6 +1856,21 @@ object SymDenotations {
case _ => ownNames
}
}
+
+ /** If another symbol with the same name is entered, unlink it,
+ * and, if symbol is a package object, invalidate the packageObj cache.
+ * @return `sym` is not already entered
+ */
+ override def proceedWithEnter(sym: Symbol, mscope: MutableScope)(implicit ctx: Context): Boolean = {
+ val entry = mscope.lookupEntry(sym.name)
+ if (entry != null) {
+ if (entry.sym == sym) return false
+ mscope.unlink(entry)
+ entry.sym.denot = sym.denot // to avoid stale symbols
+ if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId
+ }
+ true
+ }
}
class NoDenotation extends SymDenotation(
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index da6d63387..54b96a253 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -726,10 +726,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
tycon2 match {
case param2: TypeParamRef =>
- isMatchingApply(tp1) || {
- if (canConstrain(param2)) canInstantiate(param2)
- else compareLower(bounds(param2), tyconIsTypeRef = false)
- }
+ isMatchingApply(tp1) ||
+ canConstrain(param2) && canInstantiate(param2) ||
+ compareLower(bounds(param2), tyconIsTypeRef = false)
case tycon2: TypeRef =>
isMatchingApply(tp1) ||
compareLower(tycon2.info.bounds, tyconIsTypeRef = true)
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 8ae3aa7ad..e7130ee2f 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -1504,20 +1504,29 @@ object Types {
case _ => NoType
}
assert(
- (lastSymbol eq sym) ||
- (lastSymbol eq null) || {
+ (lastSymbol eq sym)
+ ||
+ (lastSymbol eq null)
+ || {
val lastDefRunId = lastDenotation match {
case d: SymDenotation => d.validFor.runId
case _ => lastSymbol.defRunId
}
(lastDefRunId != sym.defRunId) ||
(lastDefRunId == NoRunId)
- } ||
- (lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] ||
+ }
+ ||
+ lastSymbol.infoOrCompleter.isInstanceOf[ErrorType]
+ ||
+ sym.isPackageObject // package objects can be visited before we get around to index them
+ ||
sym.owner != lastSymbol.owner &&
- (sym.owner.derivesFrom(lastSymbol.owner) ||
- selfTypeOf(sym).derivesFrom(lastSymbol.owner) ||
- selfTypeOf(lastSymbol).derivesFrom(sym.owner))),
+ (sym.owner.derivesFrom(lastSymbol.owner)
+ ||
+ selfTypeOf(sym).derivesFrom(lastSymbol.owner)
+ ||
+ selfTypeOf(lastSymbol).derivesFrom(sym.owner)
+ ),
i"""data race? overwriting symbol of type $this,
|long form = $toString of class $getClass,
|last sym id = ${lastSymbol.id}, new sym id = ${sym.id},
diff --git a/tests/pos/i2200/Hello.scala b/tests/pos/i2200/Hello.scala
new file mode 100644
index 000000000..47e8b2024
--- /dev/null
+++ b/tests/pos/i2200/Hello.scala
@@ -0,0 +1,6 @@
+package bar
+import scala.language.higherKinds
+class Fix[F[_]](unfix: F[Fix[F]])
+object DocTree {
+ def docTree(s: StreamTree[DocTree]): DocTree = new Fix(s: StreamTree[DocTree])
+}
diff --git a/tests/pos/i2200/package.scala b/tests/pos/i2200/package.scala
new file mode 100644
index 000000000..3bc519b72
--- /dev/null
+++ b/tests/pos/i2200/package.scala
@@ -0,0 +1,4 @@
+package object bar {
+ type StreamTree[T] = Stream[Int]
+ type DocTree = Fix[StreamTree]
+}