From 10546245dd903a6c132253fc17ee344fbcdd8f70 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Apr 2017 13:01:14 +0200 Subject: 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. --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 73 +++++++++++++++------- compiler/src/dotty/tools/dotc/core/Types.scala | 23 ++++--- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 602848a50..d75cf2cd3 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,34 @@ 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 or the package object exists but is currently completing, + * 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 +1857,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/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}, -- cgit v1.2.3 From 756ba3d0dd5fe6f0f1dd0a954fb764503433da02 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Apr 2017 15:09:54 +0200 Subject: Tweak logic for hk type comparisons --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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) -- cgit v1.2.3 From ab101bcd299e060ad41cad2d1a91c3e32ae5267e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Apr 2017 15:09:54 +0200 Subject: Tweak logic for hk type comparisons --- tests/pos/i2200/Hello.scala | 6 ++++++ tests/pos/i2200/package.scala | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 tests/pos/i2200/Hello.scala create mode 100644 tests/pos/i2200/package.scala 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] +} -- cgit v1.2.3 From a321a982a6ebdaaa924a2538866959abe0b9eb18 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 9 Apr 2017 15:22:30 +0200 Subject: Fix documentation --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index d75cf2cd3..6d1a006ed 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1823,10 +1823,9 @@ object SymDenotations { /** Looks in both the package object and the package for members. The precise algorithm * is as follows: * - * If this is the scala package or the package object exists but is currently completing, - * 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. + * 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 -- cgit v1.2.3