From 94f8041feeddacfc188f73a9a200498ed645aee0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 17 Nov 2017 13:11:04 +0100 Subject: [PATCH 01/58] Generalize symbolic named types Make them update themselves across runs --- .../src/dotty/tools/dotc/core/Symbols.scala | 6 ++-- .../src/dotty/tools/dotc/core/Types.scala | 34 ++++++++++++++++--- .../dotc/transform/ElimErasedValueType.scala | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 85ef64c237ca..f98d9eade587 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -432,9 +432,9 @@ object Symbols { newd } - /** The initial denotation of this symbol, without going through `current` */ - final def initialDenot(implicit ctx: Context): SymDenotation = - lastDenot.initial + /** The last known denotation of this symbol, without going through `current` */ + final def lastKnownDenotation: SymDenotation = + lastDenot private[core] def defRunId: RunId = if (lastDenot == null) NoRunId else lastDenot.validFor.runId diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index faa349c911e5..fe7c280a7c70 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1627,19 +1627,31 @@ object Types { val sym = lastSymbol if (sym != null && sym.isValidInCurrentRun) denotOfSym(sym) else loadDenot case d: SymDenotation => - if (hasFixedSym) d.current - else if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) - if (nameSpace != noNameSpace || + if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) + if (hasFixedSym) + d.current + else if (nameSpace != noNameSpace || d.exists && prefix.isTightPrefix(d.owner) || d.isConstructor) d.current else recomputeMember(d) // symbol could have been overridden, recompute membership - else { + else if (hasFixedSym && d.validFor == Nowhere) // denotation was invalidated + d.current + else try { val newd = loadDenot if (newd.exists) newd else if (ctx.mode.is(Mode.Interactive)) d else d.staleSymbolError } + catch { + case ex: Error => + println(d) + println(d.validFor.runId) + println(ctx.runId) + println(hasFixedSym) + println(i"prefix = $prefix / ${prefix.member(name)}") + throw ex + } case d => if (d.validFor.runId != ctx.period.runId) loadDenot else d.current @@ -1768,10 +1780,22 @@ object Types { protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = false) + def atSig(sig: Signature): Denotation = + if (sig.ne(Signature.OverloadedSignature)) d.atSignature(sig).checkUnique + else d if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (mySig != null && mySig.ne(Signature.OverloadedSignature)) d.atSignature(mySig).checkUnique + if (d.isOverloaded) + if (hasFixedSym) { + val last = + if (lastDenotation != null) lastDenotation + else symbol.lastKnownDenotation.asSeenFrom(prefix) + atSig(last.signature) + } + else if (mySig != null) atSig(mySig) + else d else d else { // name has changed; try load in earlier phase and make current + val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current if (d.exists) d else throw new Error(s"failure to reload $this of class $getClass") diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 3de005fac34b..abce842998ee 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -86,7 +86,7 @@ class ElimErasedValueType extends MiniPhase with InfoTransformer { val site = root.thisType val info1 = site.memberInfo(sym1) val info2 = site.memberInfo(sym2) - def isDefined(sym: Symbol) = sym.initialDenot.validFor.firstPhaseId <= ctx.phaseId + def isDefined(sym: Symbol) = sym.lastKnownDenotation.initial.validFor.firstPhaseId <= ctx.phaseId if (isDefined(sym1) && isDefined(sym2) && !info1.matchesLoosely(info2)) // The reason for the `isDefined` condition is that we need to exclude mixin forwarders // from the tests. For instance, in compileStdLib, compiling scala.immutable.SetProxy, line 29: From 9d962b6b6e37b8fab005e02beaa3298de1f1de1f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 17 Nov 2017 13:52:09 +0100 Subject: [PATCH 02/58] Change isLocallyDefined criterion for TreePickler All symbols sharing the same toplevel class are now considered localy defined. Previously, this was order-dependent. --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala | 4 ++-- compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala | 6 ++---- compiler/src/dotty/tools/dotc/transform/Pickler.scala | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index fe7c280a7c70..8f63829201e0 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1638,7 +1638,7 @@ object Types { else if (hasFixedSym && d.validFor == Nowhere) // denotation was invalidated d.current else try { - val newd = loadDenot + val newd = loadDenot // TODO: If symbolic re-enter in uniques map. if (newd.exists) newd else if (ctx.mode.is(Mode.Interactive)) d else d.staleSymbolError diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala index 4d9eea150d30..a15c8c861fec 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPickler.scala @@ -6,11 +6,11 @@ package tasty import TastyFormat._ import collection.mutable import TastyBuffer._ -import core.Symbols.Symbol +import core.Symbols.{Symbol, ClassSymbol} import ast.tpd import Decorators._ -class TastyPickler { +class TastyPickler(val rootCls: ClassSymbol) { private val sections = new mutable.ArrayBuffer[(NameRef, TastyBuffer)] diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 0f727cf8f101..d8f87cbc007d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -73,10 +73,8 @@ class TreePickler(pickler: TastyPickler) { forwardSymRefs(sym) = ref :: forwardSymRefs.getOrElse(sym, Nil) } - private def isLocallyDefined(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { - case Some(label) => assert(sym.exists); label != NoAddr - case None => false - } + private def isLocallyDefined(sym: Symbol)(implicit ctx: Context) = + sym.topLevelClass.isLinkedWith(pickler.rootCls) def pickleConstant(c: Constant)(implicit ctx: Context): Unit = c.tag match { case UnitTag => diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index d1396491f702..4e4ede5f429f 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -43,7 +43,7 @@ class Pickler extends Phase { for { cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree)) tree <- sliceTopLevel(unit.tpdTree, cls) } { - val pickler = new TastyPickler() + val pickler = new TastyPickler(cls) if (ctx.settings.YtestPickler.value) { beforePickling(cls) = tree.show picklers(cls) = pickler From 30395c89ee52d20384b06cd92fed98341b4bc485 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 17 Nov 2017 14:04:11 +0100 Subject: [PATCH 03/58] Cater for external symbolic references in pickler --- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index d8f87cbc007d..8cfb3411892d 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -146,6 +146,19 @@ class TreePickler(pickler: TastyPickler) { writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) pickleSymRef(sym) } + def pickleExternalRef(sym: Symbol) = + if (sym.is(Flags.Private)) { + writeByte(if (tpe.isType) TYPEREFin else TERMREFin) + withLength { + pickleName(sym.name) + pickleType(tpe.prefix) + pickleType(sym.owner.typeRef) + } + } + else { + writeByte(if (tpe.isType) TYPEREF else TERMREF) + pickleName(sym.name); pickleType(tpe.prefix) + } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) pickleName(sym.fullName) @@ -176,6 +189,8 @@ class TreePickler(pickler: TastyPickler) { pickleType(tpe.prefix) pickleType(space) } + case sym: Symbol => + pickleExternalRef(sym) } case tpe: ThisType => if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) { From e0866d4c4fb6b68bf289f6d6839491abf20b4f50 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Nov 2017 12:44:10 +0100 Subject: [PATCH 04/58] Allow pickling of general symbolic references --- .../tools/dotc/core/tasty/TreePickler.scala | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 8cfb3411892d..fbb0a6347b26 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -55,6 +55,11 @@ class TreePickler(pickler: TastyPickler) { private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) + private def pickleNameAndSig(name: Name, sig: Signature): Unit = + pickleName( + if (sig eq Signature.NotAMethod) name + else SignedName(name.toTermName, sig)) + private def pickleSymRef(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { case Some(label) => if (label != NoAddr) writeRef(label) else pickleForwardSymRef(sym) @@ -146,19 +151,23 @@ class TreePickler(pickler: TastyPickler) { writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) pickleSymRef(sym) } - def pickleExternalRef(sym: Symbol) = + def pickleExternalRef(sym: Symbol) = { + def pickleCore() = { + pickleNameAndSig(sym.name, tpe.signature) + pickleType(tpe.prefix) + } if (sym.is(Flags.Private)) { writeByte(if (tpe.isType) TYPEREFin else TERMREFin) withLength { - pickleName(sym.name) - pickleType(tpe.prefix) + pickleCore() pickleType(sym.owner.typeRef) } } else { writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(sym.name); pickleType(tpe.prefix) + pickleCore() } + } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) pickleName(sym.fullName) @@ -340,9 +349,7 @@ class TreePickler(pickler: TastyPickler) { case Select(qual, name) => writeByte(if (name.isTypeName) SELECTtpt else SELECT) val sig = tree.tpe.signature - pickleName( - if (sig eq Signature.NotAMethod) name - else SignedName(name.toTermName, sig)) + pickleNameAndSig(name, sig) pickleTree(qual) case Apply(fun, args) => writeByte(APPLY) From 68760a47eaabfb8ef1ec19d3062c15b68e5c7326 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Nov 2017 13:00:33 +0100 Subject: [PATCH 05/58] Create OverloadedSymbol and OverloadedDenotation Will be needed to represent overloaded TermRefs --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 11 +++++++---- compiler/src/dotty/tools/dotc/core/Symbols.scala | 12 ++++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ca7a889affeb..5630233c095b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1852,10 +1852,9 @@ object SymDenotations { } } - class NoDenotation extends SymDenotation( - NoSymbol, NoSymbol, "".toTermName, Permanent, NoType) { + class NoDenotation(sym: Symbol, name: Name, override val isTerm: Boolean) + extends SymDenotation(sym, NoSymbol, name, Permanent, NoType) { override def exists = false - override def isTerm = false override def isType = false override def owner: Symbol = throw new AssertionError("NoDenotation.owner") override def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = this @@ -1863,7 +1862,11 @@ object SymDenotations { validFor = Period.allInRun(NoRunId) } - @sharable val NoDenotation = new NoDenotation + @sharable val NoDenotation = + new NoDenotation(NoSymbol, "".toTermName, isTerm = false) + + @sharable val OverloadedDenotation = + new NoDenotation(OverloadedSymbol, "".toTermName, isTerm = true) // ---- Completion -------------------------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index f98d9eade587..352b1e29550d 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -648,12 +648,20 @@ object Symbols { denot = underlying.denot } - @sharable object NoSymbol extends Symbol(NoCoord, 0) { - denot = NoDenotation + class NonExistingSymbol extends Symbol(NoCoord, 0) { override def associatedFile(implicit ctx: Context): AbstractFile = NoSource.file override def recomputeDenot(lastd: SymDenotation)(implicit ctx: Context): SymDenotation = NoDenotation } + @sharable object NoSymbol extends NonExistingSymbol { + denot = NoDenotation + } + + @sharable object OverloadedSymbol extends NonExistingSymbol { + denot = OverloadedDenotation + type ThisName = TermName + } + implicit class Copier[N <: Name](sym: Symbol { type ThisName = N })(implicit ctx: Context) { /** Copy a symbol, overriding selective fields */ def copy( From 0864141f1d13a74558c57e75208ce55ab6a4813d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Nov 2017 13:02:55 +0100 Subject: [PATCH 06/58] More robust implementation of requiredMethod Test types arguments for equality with =:= rather than ==. Also, better diagnostics for requiredSymbol --- .../src/dotty/tools/dotc/core/Denotations.scala | 16 +++++++++++----- .../dotty/tools/dotc/typer/TypeAssigner.scala | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index c3294acc1621..bf7c39b09ea5 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -200,7 +200,7 @@ object Denotations { } else NoSymbol case NoDenotation | _: NoQualifyingRef => - throw new TypeError(s"None of the alternatives of $this satisfies required predicate") + throw new TypeError(i"None of the alternatives of $this satisfies required predicate") case denot => denot.symbol } @@ -210,10 +210,16 @@ object Denotations { def requiredMethodRef(name: PreName)(implicit ctx: Context): TermRef = requiredMethod(name).termRef - def requiredMethod(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = - info.member(name.toTermName).requiredSymbol(x=> - (x is Method) && x.info.paramInfoss == List(argTypes) - ).asTerm + def requiredMethod(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermSymbol = { + info.member(name.toTermName).requiredSymbol { x => + (x is Method) && { + x.info.paramInfoss match { + case paramInfos :: Nil => paramInfos.corresponds(argTypes)(_ =:= _) + case _ => false + } + } + }.asTerm + } def requiredMethodRef(name: PreName, argTypes: List[Type])(implicit ctx: Context): TermRef = requiredMethod(name, argTypes).termRef diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 13f2dbb1c316..40a46f0686bb 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -413,6 +413,7 @@ trait TypeAssigner { else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.pos) } case _ => + //println(i"bad type: $fn: ${fn.symbol} / ${fn.symbol.isType} / ${fn.symbol.info}") // DEBUG errorType(err.takesNoParamsStr(fn, "type "), tree.pos) } From 12c4429f426f479f72c6cee73a6921b9b4d8358f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Nov 2017 13:04:58 +0100 Subject: [PATCH 07/58] Optionally make NamedTypes symbolic For now it's controlled under a config option. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 7 +- .../src/dotty/tools/dotc/config/Config.scala | 4 +- .../tools/dotc/core/SymDenotations.scala | 14 +- .../src/dotty/tools/dotc/core/Symbols.scala | 15 ++- .../src/dotty/tools/dotc/core/Types.scala | 121 +++++++++++++----- .../dotc/core/classfile/ClassfileParser.scala | 5 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 41 ++++-- .../core/unpickleScala2/Scala2Unpickler.scala | 10 +- .../dotc/transform/ParamForwarding.scala | 8 +- .../tools/dotc/transform/PostTyper.scala | 3 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- tests/run/t3452h.scala | 17 ++- tests/run/unittest_collection.scala | 58 --------- 14 files changed, 178 insertions(+), 131 deletions(-) delete mode 100644 tests/run/unittest_collection.scala diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 334e2a467476..a622a75e6c53 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -709,7 +709,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val tp = if (sym.isType) { assert(!sym.is(TypeParam)) - TypeRef(tree.tpe, sym.name.asTypeName) + if (config.Config.newScheme) TypeRef.withSym(tree.tpe, sym.asType) + else TypeRef.applyOLD(tree.tpe, sym.name.asTypeName) } else TermRef(tree.tpe, sym.name.asTermName, sym.denot.asSeenFrom(tree.tpe)) @@ -719,7 +720,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A select node with the given selector name and signature and a computed type */ def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context): Tree = untpd.SelectWithSig(tree, name, sig) - .withType(TermRef(tree.tpe, name.asTermName.withSig(sig))) + .withType( + if (config.Config.newScheme) tree.tpe.select(name.asTermName, sig) + else TermRef.applyOLD(tree.tpe, name.asTermName.withSig(sig))) /** A select node with selector name and signature taken from `sym`. * Note: Use this method instead of select(sym) if the referenced symbol diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 60108d51d236..d7f5985177fb 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -148,7 +148,7 @@ object Config { final val showCompletions = false /** If set, enables tracing */ - final val tracingEnabled = false + final val tracingEnabled = true /** Initial capacity of uniques HashMap. * Note: This MUST BE a power of two to work with util.HashSet @@ -179,4 +179,6 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true + + val newScheme = false } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 5630233c095b..69378455b290 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1134,10 +1134,12 @@ object SymDenotations { def thisType(implicit ctx: Context): Type = NoPrefix override def typeRef(implicit ctx: Context): TypeRef = - TypeRef(owner.thisType, name.asTypeName, this) + if (Config.newScheme) TypeRef.withSym(owner.thisType, symbol.asType) + else TypeRef(owner.thisType, name.asTypeName, this) override def termRef(implicit ctx: Context): TermRef = - TermRef(owner.thisType, name.asTermName, this) + if (Config.newScheme) TermRef.withSym(owner.thisType, symbol.asTerm) + else TermRef(owner.thisType, name.asTermName, this) /** The variance of this type parameter or type member as an Int, with * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter @@ -1852,10 +1854,10 @@ object SymDenotations { } } - class NoDenotation(sym: Symbol, name: Name, override val isTerm: Boolean) + class NoDenotation(sym: Symbol, name: Name, override val exists: Boolean) extends SymDenotation(sym, NoSymbol, name, Permanent, NoType) { - override def exists = false override def isType = false + override def isTerm = exists override def owner: Symbol = throw new AssertionError("NoDenotation.owner") override def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = this override def mapInfo(f: Type => Type)(implicit ctx: Context): SingleDenotation = this @@ -1863,10 +1865,10 @@ object SymDenotations { } @sharable val NoDenotation = - new NoDenotation(NoSymbol, "".toTermName, isTerm = false) + new NoDenotation(NoSymbol, "".toTermName, exists = false) @sharable val OverloadedDenotation = - new NoDenotation(OverloadedSymbol, "".toTermName, isTerm = true) + new NoDenotation(OverloadedSymbol, "".toTermName, exists = true) // ---- Completion -------------------------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 352b1e29550d..273dc47271a0 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -158,7 +158,9 @@ trait Symbols { this: Context => infoFn(module, modcls), privateWithin) val mdenot = SymDenotation( module, owner, name, modFlags | ModuleValCreationFlags, - if (cdenot.isCompleted) TypeRef.withSym(owner.thisType, modcls, modclsName) + if (cdenot.isCompleted) + if (config.Config.newScheme) TypeRef.withSym(owner.thisType, modcls) + else TypeRef.withSymOLD(owner.thisType, modcls, modclsName) else new ModuleCompleter(modcls)) module.denot = mdenot modcls.denot = cdenot @@ -183,7 +185,9 @@ trait Symbols { this: Context => newModuleSymbol( owner, name, modFlags, clsFlags, (module, modcls) => ClassInfo( - owner.thisType, modcls, parents, decls, TermRef.withSym(owner.thisType, module, name)), + owner.thisType, modcls, parents, decls, + if (config.Config.newScheme) TermRef.withSym(owner.thisType, module) + else TermRef.withSymOLD(owner.thisType, module, name)), privateWithin, coord, assocFile) val companionMethodFlags = Flags.Synthetic | Flags.Private | Flags.Method @@ -291,7 +295,10 @@ trait Symbols { this: Context => for (name <- names) { val tparam = newNakedSymbol[TypeName](NoCoord) tparamBuf += tparam - trefBuf += TypeRef.withSym(owner.thisType, tparam, name) + trefBuf += ( + if (config.Config.newScheme) TypeRef.withSym(owner.thisType, tparam) + else TypeRef.withSymOLD(owner.thisType, tparam, name) + ) } val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) @@ -469,7 +476,7 @@ object Symbols { */ final def isReferencedSymbolically(implicit ctx: Context) = { val d = lastDenot - d != null && (d.is(NonMember) || d.isTerm && ctx.phase.symbolicRefs) + d != null && (d.is(NonMember) || ctx.phase.symbolicRefs) } /** Test whether symbol is private. This diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8f63829201e0..88b1d32a0ae6 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1134,11 +1134,21 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = - NamedType(this, name).reduceProjection + if (Config.newScheme) NamedType.withDenot(this, member(name)).reduceProjection + else NamedType.applyOLD(this, name).reduceProjection + + def select(name: TermName)(implicit ctx: Context): TermRef = + if (Config.newScheme) TermRef.withDenot(this, member(name)) + else TermRef.applyOLD(this, name) + + def select(name: TermName, sig: Signature)(implicit ctx: Context): TermRef = { + assert(Config.newScheme) + TermRef.withDenot(this, member(name).atSignature(sig)) + } /** The type , reduced if possible, with given denotation if unreduced */ - def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = - NamedType(this, name, denot).reduceProjection + def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = // ### drop name + NamedType.apply(this, name, denot).reduceProjection /** The type with either `sym` or its signed name as designator, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = @@ -1625,7 +1635,11 @@ object Types { val d = lastDenotation match { case null => val sym = lastSymbol - if (sym != null && sym.isValidInCurrentRun) denotOfSym(sym) else loadDenot + if (sym != null && sym.isValidInCurrentRun && + (!Config.newScheme || + (prefix eq NoPrefix) || (prefix eq sym.owner.thisType) || sym.isReferencedSymbolically)) + denotOfSym(sym) + else loadDenot case d: SymDenotation => if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) if (hasFixedSym) @@ -1733,8 +1747,10 @@ object Types { this else if (signature != denot.signature) withSig(denot.signature) - else if (denot.symbol.isPrivate) - withNameSpace(denot.symbol.owner.typeRef) + else if (denot.symbol.isPrivate) { + assert(!Config.newScheme) + withNameSpaceOLD(denot.symbol.owner.typeRef) + } else this if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] @@ -1775,11 +1791,13 @@ object Types { checkedPeriod = Nowhere } - private def withSig(sig: Signature)(implicit ctx: Context): NamedType = - TermRef(prefix, designator.withSig(sig)) + private def withSig(sig: Signature)(implicit ctx: Context): NamedType = { + assert(!Config.newScheme) + TermRef.applyOLD(prefix, designator.withSig(sig)) + } protected def loadDenot(implicit ctx: Context): Denotation = { - val d = asMemberOf(prefix, allowPrivate = false) + val d = asMemberOf(prefix, allowPrivate = Config.newScheme && hasFixedSym) def atSig(sig: Signature): Denotation = if (sig.ne(Signature.OverloadedSignature)) d.atSignature(sig).checkUnique else d @@ -1954,9 +1972,9 @@ object Types { /** Create a NamedType of the same kind as this type, but with a new namespace. */ - def withNameSpace(nameSpace: NameSpace)(implicit ctx: Context): NamedType = + def withNameSpaceOLD(nameSpace: NameSpace)(implicit ctx: Context): NamedType = if (nameSpace == this.nameSpace) this - else NamedType(prefix, designator.withNameSpace(nameSpace)) + else NamedType.applyOLD(prefix, designator.withNameSpace(nameSpace)) override def equals(that: Any) = that match { case that: NamedType => @@ -1994,7 +2012,8 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef(prefix, name, sd) + if (Config.newScheme) TermRef.withDenot(prefix, sd) + else TermRef.apply(prefix, name, sd) def alternatives(implicit ctx: Context): List[TermRef] = denot.alternatives map rewrap @@ -2028,7 +2047,8 @@ object Types { designator.withSig(newSig) } else designator - fixDenot(TermRef(prefix, designator1), prefix) + assert(!Config.newScheme) + fixDenot(TermRef.applyOLD(prefix, designator1), prefix) } } @@ -2040,7 +2060,8 @@ object Types { override def underlying(implicit ctx: Context): Type = info def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = - TypeRef(prefix, designator) + if (Config.newScheme) TypeRef(prefix, designator.asInstanceOf[TypeSymbol]) + else TypeRef.applyOLD(prefix, designator) } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { @@ -2058,12 +2079,19 @@ object Types { if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) object NamedType { - def apply(prefix: Type, designator: Designator)(implicit ctx: Context) = + def applyOLD(prefix: Type, designator: Designator)(implicit ctx: Context) = + if (designator.isType) TypeRef.applyOLD(prefix, designator.asType) + else TermRef.applyOLD(prefix, designator.asTerm) + def apply(prefix: Type, designator: Symbol)(implicit ctx: Context) = if (designator.isType) TypeRef(prefix, designator.asType) else TermRef(prefix, designator.asTerm) + def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context) = + if (denot.isTerm) TermRef.withDenot(prefix, denot) + else TypeRef.withDenot(prefix, denot) def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = - if (designator.isTermName) TermRef(prefix, designator.asTermName, denot) - else TypeRef(prefix, designator.asTypeName, denot) + if (Config.newScheme) withDenot(prefix, denot) + else if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) + else TypeRef.apply(prefix, designator.asTypeName, denot) def withSym(prefix: Type, sym: Symbol)(implicit ctx: Context): NamedType = if (sym.isType) TypeRef.withSym(prefix, sym.asType) else TermRef.withSym(prefix, sym.asTerm) @@ -2075,7 +2103,10 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def apply(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = + def applyOLD(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = + ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] + + def apply(prefix: Type, designator: TermSymbol)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] /** Create term ref to given initial denotation, taking the signature @@ -2083,50 +2114,62 @@ object Types { * signature, if denotation is not yet completed. */ def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) + if (Config.newScheme) withDenot(prefix, denot) + else if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) else denot match { case denot: SingleDenotation => - apply(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) - case _ => apply(prefix, name) + applyOLD(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) + case _ => applyOLD(prefix, name) } } withDenot denot + def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TermRef = + apply(prefix, denot.symbol.asTerm).withDenot(denot) + /** Create a term ref referring to given symbol with given name. * This is similar to TermRef(Type, Symbol), except: * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. * (2) the designator of the TermRef is either the symbol or its name & unforced signature. */ - def withSym(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = + def withSymOLD(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) + else applyOLD(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - withSym(prefix, sym, sym.name) + if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) } object TypeRef { /** Create type ref with given prefix and name */ - def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = + def applyOLD(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = + ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] + + /** Create type ref with given prefix and name */ + def apply(prefix: Type, desig: TypeSymbol)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref with given name and initial denotation */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) - else apply(prefix, name.localizeIfPrivate(denot.symbol)) + if (Config.newScheme) withDenot(prefix, denot) + else if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) + else applyOLD(prefix, name.localizeIfPrivate(denot.symbol)) } withDenot denot + def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TypeRef = + apply(prefix, denot.symbol.asType).withDenot(denot) + /** Create a type ref referring to either a given symbol or its name. * This is similar to TypeRef(prefix, sym), except: * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. * (2) the designator of the TypeRef is either the symbol or its name */ - def withSym(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = + def withSymOLD(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name.localizeIfPrivate(sym)).withSym(sym) + else applyOLD(prefix, name.localizeIfPrivate(sym)).withSym(sym) def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - withSym(prefix, sym, sym.name) + if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) } // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- @@ -3472,7 +3515,8 @@ object Types { if (appliedRefCache == null) { val tref = if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef // ??? not always symbolicRef - else TypeRef(prefix, cls.name, clsDenot) + else if (Config.newScheme) TypeRef.withDenot(prefix, clsDenot) + else TypeRef.apply(prefix, cls.name, clsDenot) appliedRefCache = tref.appliedTo(cls.typeParams.map(_.typeRef)) } @@ -3554,7 +3598,20 @@ object Types { case tp: ClassInfo => // Note: Taking a normal typeRef does not work here. A normal ref might contain // also other information about the named type (e.g. bounds). - contains(tp.symbolicTypeRef) // ??? not clear + if (Config.newScheme) { + val loOK = + lo.isRef(tp.cls) || + lo.isRef(defn.NothingClass) || + lo.isRef(defn.NullClass) && !tp.cls.isValueClass + val hiOK = + hi.isRef(tp.cls) || + tp.parents.exists(p => p <:< hi) + loOK && hiOK || { + println(i"NOT CONTAINS: $this / $tp") + false + } + } + else contains(tp.symbolicTypeRef) case _ => lo <:< tp && tp <:< hi } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index e13311ddeb4d..43ceaaaad83c 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -319,7 +319,10 @@ class ClassfileParser( case 'L' => def processInner(tp: Type): Type = tp match { case tp: TypeRef if !(tp.symbol.owner is Flags.ModuleClass) => - TypeRef.withSym(processInner(tp.prefix.widen), tp.symbol.asType, tp.name) + if (config.Config.newScheme) + TypeRef.withSym(processInner(tp.prefix.widen), tp.symbol.asType) + else + TypeRef.withSymOLD(processInner(tp.prefix.widen), tp.symbol.asType, tp.name) case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 09677d9490ec..aefe43477c69 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -222,15 +222,24 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val result = (tag: @switch) match { case TERMREFin => - var name = readName() + var sname = readName() val prefix = readType() val space = readType().asInstanceOf[TypeRef] - TermRef(prefix, name.withNameSpace(space)) + if (Config.newScheme) { + val d = sname match { + case SignedName(name, sig) => space.decl(name).atSignature(sig) + case name => space.decl(name) + } + assert(d.symbol.exists) + TermRef.withDenot(prefix, d) + } + else TermRef.applyOLD(prefix, sname.withNameSpace(space)) case TYPEREFin => val name = readName().toTypeName val prefix = readType() val space = readType().asInstanceOf[TypeRef] - TypeRef(prefix, name.withNameSpace(space)) + if (Config.newScheme) TermRef.withDenot(prefix, space.decl(name)) + else TypeRef.applyOLD(prefix, name.withNameSpace(space)) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -287,11 +296,23 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case TERMREFpkg => readPackageRef().termRef case TYPEREF => - val name = readName().toTypeName - TypeRef(readType(), name) + val name = readName().toTypeName + if (Config.newScheme) { + val prefix = readType() + TypeRef.withDenot(prefix, prefix.member(name)) + } + else TypeRef.applyOLD(readType(), name) case TERMREF => - val name = readName() - TermRef(readType(), name) + val sname = readName() + if (Config.newScheme) { + val prefix = readType() + val d = sname match { + case SignedName(name, sig) => prefix.member(name).atSignature(sig) + case name => prefix.member(name) + } + TermRef.withDenot(prefix, d) + } + else TermRef.applyOLD(readType(), sname) case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) case RECtype => @@ -343,7 +364,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val prefix = readType() val res = NamedType.withSym(prefix, sym) prefix match { - case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot) + case prefix: ThisType if !Config.newScheme && (prefix.cls eq sym.owner) => res.withDenot(sym.denot) // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala // the problem arises when a self type of a trait is a type parameter of the same trait. case _ => res @@ -723,8 +744,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val start = currentAddr val cls = ctx.owner.asClass val assumedSelfType = - if (cls.is(Module) && cls.owner.isClass) - TermRef(cls.owner.thisType, cls.name.sourceModuleName.localizeIfPrivate(cls)) + if (cls.is(Module) && cls.owner.isClass && !Config.newScheme /*???*/) + TermRef.applyOLD(cls.owner.thisType, cls.name.sourceModuleName.localizeIfPrivate(cls)) else NoType cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index c08da6aa2559..c33b05ae31c7 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -702,8 +702,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case SINGLEtpe => val pre = readTypeRef() val sym = readDisambiguatedSymbolRef(_.info.isParameterless) - if (isLocal(sym) || (pre eq NoPrefix)) pre select sym - else TermRef(pre, sym.name.asTermName) + if (config.Config.newScheme || isLocal(sym) || (pre eq NoPrefix)) pre select sym + else TermRef.applyOLD(pre, sym.name.asTermName) case SUPERtpe => val thistpe = readTypeRef() val supertpe = readTypeRef() @@ -731,11 +731,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case _ => } val tycon = - if (sym.isClass && sym.is(Scala2x) && sym.owner.isClass && !sym.owner.is(Package)) + if (!config.Config.newScheme && sym.isClass && sym.is(Scala2x) && sym.owner.isClass && !sym.owner.is(Package)) // There can be multiple Scala2 inner classes with the same prefix and name; use a namespace // to pick a particular one. - TypeRef(pre, sym.name.asTypeName.withNameSpace(sym.owner.typeRef)) - else if (isLocal(sym) || pre == NoPrefix) { + TypeRef.applyOLD(pre, sym.name.asTypeName.withNameSpace(sym.owner.typeRef)) + else if (config.Config.newScheme || isLocal(sym) || pre == NoPrefix) { val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre pre1 select sym } diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 901b1a316211..354e482343c6 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -69,11 +69,11 @@ class ParamForwarding(thisPhase: DenotTransformer) { .installAfter(thisPhase) var superAcc = Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias) - if (alias.owner != currentClass.superClass) + if (alias.owner != currentClass.superClass && !config.Config.newScheme) // need to use shadowed in order not to accidentally address an // intervening private forwarder in the superclass superAcc = superAcc.withType( - superAcc.tpe.asInstanceOf[TermRef].withNameSpace(noNameSpace)) + superAcc.tpe.asInstanceOf[TermRef].withNameSpaceOLD(noNameSpace)) typr.println(i"adding param forwarder $superAcc") DefDef(sym, superAcc.ensureConforms(sym.info.widen)) } @@ -93,12 +93,12 @@ class ParamForwarding(thisPhase: DenotTransformer) { def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree.tpe match { case tpe: TermRef - if tpe.prefix.ne(NoPrefix) && tpe.signature.eq(Signature.NotAMethod) && tpe.symbol.is(Method) => + if !config.Config.newScheme && tpe.prefix.ne(NoPrefix) && tpe.signature.eq(Signature.NotAMethod) && tpe.symbol.is(Method) => // It could be a param forwarder; adapt the signature val newSig = tpe.prefix.memberInfo(tpe.symbol).signature if (newSig.eq(Signature.NotAMethod)) tree else tree.withType( - TermRef(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) + TermRef.applyOLD(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) .asInstanceOf[T] case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 8ad6cee9e2af..c7b945923199 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -85,8 +85,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase */ private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree.tpe match { case tpe: TermRef if tpe.signature.isUnderDefined => + assert(!config.Config.newScheme) typr.println(i"fixing $tree with type ${tree.tpe.widen.toString} with sig ${tpe.signature} to ${tpe.widen.signature}") - tree.withType(TermRef(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] + tree.withType(TermRef.applyOLD(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index e922a1a55c14..254bca871396 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -432,7 +432,7 @@ trait ImplicitRunInfo { self: RunInfo => def addRef(companion: TermRef): Unit = { val compSym = companion.symbol if (compSym is Package) - addRef(TermRef(companion, nme.PACKAGE)) + addRef(companion.select(nme.PACKAGE)) else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 40a46f0686bb..9c1c7e0433d9 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -187,8 +187,8 @@ trait TypeAssigner { // it could be that we found an inaccessible private member, but there is // an inherited non-private member with the same name and signature. val d2 = pre.nonPrivateMember(name) - if (reallyExists(d2) && firstTry) - test(tpe.withNameSpace(noNameSpace).withDenot(d2), false) + if (reallyExists(d2) && firstTry && !config.Config.newScheme) + test(tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { TryDynamicCallType } else { diff --git a/tests/run/t3452h.scala b/tests/run/t3452h.scala index c06ae0a0b08d..d61fb065ba99 100644 --- a/tests/run/t3452h.scala +++ b/tests/run/t3452h.scala @@ -1,8 +1,17 @@ -class Mix___eFoo_I_wBar__f extends Foo_I_ with Bar__f { f; } +class Mix extends Foo with Bar { f; } trait T -abstract class Foo_I_ { class I extends T ; def f: I ; f; } -trait Bar__f { type I>:Null<:T; def f: I = {null}; f; def gobble: I = {null}} +abstract class Foo { + class I extends T + def f: I + f +} +trait Bar { + type I >: Null <: T + def f: I = null + f + def gobble: I = null +} object Test extends dotty.runtime.LegacyApp { - new Mix___eFoo_I_wBar__f + new Mix } diff --git a/tests/run/unittest_collection.scala b/tests/run/unittest_collection.scala deleted file mode 100644 index 8be8ea1a5927..000000000000 --- a/tests/run/unittest_collection.scala +++ /dev/null @@ -1,58 +0,0 @@ -object Test { - - import scala.collection.mutable.{ArrayBuffer, Buffer, BufferProxy, ListBuffer} - - def main(args: Array[String]): Unit = { - test(collection.mutable.ArrayBuffer[String]()) - test(collection.mutable.ListBuffer[String]()) - class BBuf(z:ListBuffer[String]) extends BufferProxy[String] { // @odersky - bug here in scala 2.12 trait encoding seems like... - def self = z - } - test(new BBuf(collection.mutable.ListBuffer[String]())) - } - - def test(x: Buffer[String]): Unit = { - // testing method += - x += "one" - assert(x(0) == "one", "retrieving 'one'") - assert(x.length == 1, "length A") - x += "two" - assert(x(1) == "two", "retrieving 'two'") - assert(x.length == 2, "length B") - - // testing method -= (removing last element) - x -= "two" - - assert(x.length == 1, "length C") - - try { x(1); sys.error("no exception for removed element") } - catch { case i:IndexOutOfBoundsException => } - - try { x.remove(1); sys.error("no exception for removed element") } - catch { case i:IndexOutOfBoundsException => } - - x += "two2" - assert(x.length == 2, "length D") - - // removing first element - x.remove(0) - assert(x.length == 1, "length E") - - // toList - assert(x.toList == List("two2"), "toList") - - // clear - x.clear() - assert(x.length == 0, "length 0") - assert(x.isEmpty, "isEmpty") - - // copyToBuffer - x += "a" - x += "b" - val dest = new ArrayBuffer[String] - x.copyToBuffer(dest) - assert(List("a", "b") == dest.toList, "dest") - assert(List("a", "b") == x.toList, "source") - } - -} From 2399c68e42a7233f7d3088dbbada09ef2fc1da01 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 13:32:16 +0100 Subject: [PATCH 08/58] Fix Erasure's transformDenot for SingleDenotations They wold transform the pre-existing type of the denotation instead of the symbol's type. This is clearly the wrong behavior for erasure. It was not detected before because we changed all types from name-based to symbolic during erasure, which meant we computed the denotation after erasure by a loadDenot. So we never exercised the `d.current` code on a derived denotation. --- compiler/src/dotty/tools/dotc/transform/Erasure.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index ecb40b52a910..8b093a29a3fb 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -86,7 +86,7 @@ class Erasure extends Phase with DenotTransformer { } } case ref => - ref.derivedSingleDenotation(ref.symbol, transformInfo(ref.symbol, ref.info)) + ref.derivedSingleDenotation(ref.symbol, transformInfo(ref.symbol, ref.symbol.info)) } val eraser = new Erasure.Typer From cea18233c19f28473413c972c7957dfed9086d52 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 13:39:55 +0100 Subject: [PATCH 09/58] Drop OverloadedSymbol/Denotation It caused errors even in the old scheme, because we now had another symbol that "existed" yet did not have an owner. Also, change creation methods for NamedTypes to accommodate NoSymbol as a symbol of an overloaded denotation. --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 6 ++---- compiler/src/dotty/tools/dotc/core/Symbols.scala | 11 ++--------- compiler/src/dotty/tools/dotc/core/Types.scala | 8 ++++---- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 69378455b290..004f15ba4c9a 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1861,15 +1861,13 @@ object SymDenotations { override def owner: Symbol = throw new AssertionError("NoDenotation.owner") override def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = this override def mapInfo(f: Type => Type)(implicit ctx: Context): SingleDenotation = this + sym.denot = this validFor = Period.allInRun(NoRunId) } - @sharable val NoDenotation = + @sharable val NoDenotation: NoDenotation = new NoDenotation(NoSymbol, "".toTermName, exists = false) - @sharable val OverloadedDenotation = - new NoDenotation(OverloadedSymbol, "".toTermName, exists = true) - // ---- Completion -------------------------------------------------------- /** Instances of LazyType are carried by uncompleted symbols. diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 273dc47271a0..ed4dce6bf292 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -655,19 +655,12 @@ object Symbols { denot = underlying.denot } - class NonExistingSymbol extends Symbol(NoCoord, 0) { + @sharable val NoSymbol = new Symbol(NoCoord, 0) { override def associatedFile(implicit ctx: Context): AbstractFile = NoSource.file override def recomputeDenot(lastd: SymDenotation)(implicit ctx: Context): SymDenotation = NoDenotation } - @sharable object NoSymbol extends NonExistingSymbol { - denot = NoDenotation - } - - @sharable object OverloadedSymbol extends NonExistingSymbol { - denot = OverloadedDenotation - type ThisName = TermName - } + NoDenotation // force it in order to set `denot` field of NoSymbol implicit class Copier[N <: Name](sym: Symbol { type ThisName = N })(implicit ctx: Context) { /** Copy a symbol, overriding selective fields */ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 88b1d32a0ae6..3abd464753df 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2106,7 +2106,7 @@ object Types { def applyOLD(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] - def apply(prefix: Type, designator: TermSymbol)(implicit ctx: Context): TermRef = + def apply(prefix: Type, designator: Symbol)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] /** Create term ref to given initial denotation, taking the signature @@ -2124,7 +2124,7 @@ object Types { } withDenot denot def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TermRef = - apply(prefix, denot.symbol.asTerm).withDenot(denot) + apply(prefix, denot.symbol).withDenot(denot) /** Create a term ref referring to given symbol with given name. * This is similar to TermRef(Type, Symbol), except: @@ -2146,7 +2146,7 @@ object Types { ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create type ref with given prefix and name */ - def apply(prefix: Type, desig: TypeSymbol)(implicit ctx: Context): TypeRef = + def apply(prefix: Type, desig: Symbol)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref with given name and initial denotation */ @@ -2157,7 +2157,7 @@ object Types { } withDenot denot def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TypeRef = - apply(prefix, denot.symbol.asType).withDenot(denot) + apply(prefix, denot.symbol).withDenot(denot) /** Create a type ref referring to either a given symbol or its name. * This is similar to TypeRef(prefix, sym), except: From 832689090ff043e0ae60ae1ca141b1c6468a5e7b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 16:30:04 +0100 Subject: [PATCH 10/58] Don't interpolate or simplify overloaded references Simplifying an overloaded reference risks changing the prefix, which will lead into trouble using the new overloading scheme (because the only info is in the denotation, which will be thrown away when the prefix is changed). Also, both interpolating undetermined variables and simplifying are likely to be inefficient on overloaded types because they tend to be large. Delaying these operations means we only have to perform them on alternatives that might plausibly match the expected type. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ee824534d6d0..196c9c43e880 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1902,9 +1902,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = /*>|>*/ track("adapt") /*<|<*/ { /*>|>*/ trace(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ { - if (tree.isDef) interpolateUndetVars(tree, tree.symbol) - else if (!tree.tpe.widen.isInstanceOf[LambdaType]) interpolateUndetVars(tree, NoSymbol) - tree.overwriteType(tree.tpe.simplified) + if (!tree.denot.isOverloaded) { + // for overloaded trees: resolve overloading before simplifying + if (tree.isDef) interpolateUndetVars(tree, tree.symbol) + else if (!tree.tpe.widen.isInstanceOf[LambdaType]) interpolateUndetVars(tree, NoSymbol) + tree.overwriteType(tree.tpe.simplified) + } adaptInterpolated(tree, pt) } } From a9291b4dc8ffba5fac35ef3d348e9acd8f1da459 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 19:30:40 +0100 Subject: [PATCH 11/58] Rework denotations Make PreDenotation a superclass of Denotation. The immediate need for this is that we would like to add an `asSeenFrom` to Denotations, but if we do that it clashes with the `asSeenFrom` in Predenotations. --- .../dotty/tools/dotc/core/Denotations.scala | 311 ++++++++++-------- 1 file changed, 169 insertions(+), 142 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index bf7c39b09ea5..e99a931676e3 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -72,6 +72,78 @@ object Denotations { implicit def eqDenotation: Eq[Denotation, Denotation] = Eq + /** A PreDenotation represents a group of single denotations or a single multi-denotation + * It is used as an optimization to avoid forming MultiDenotations too eagerly. + */ + abstract class PreDenotation extends util.DotClass { + + /** A denotation in the group exists */ + def exists: Boolean + + /** First/last denotation in the group */ + def first: Denotation + def last: Denotation + + /** Convert to full denotation by &-ing all elements */ + def toDenot(pre: Type)(implicit ctx: Context): Denotation + + /** Group contains a denotation that refers to given symbol */ + def containsSym(sym: Symbol): Boolean + + /** Group contains a denotation with the same signature as `other` */ + def matches(other: SingleDenotation)(implicit ctx: Context): Boolean + + /** Keep only those denotations in this group which satisfy predicate `p`. */ + def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation + + /** Keep only those denotations in this group which have a signature + * that's not already defined by `denots`. + */ + def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation + + /** Keep only those inherited members M of this predenotation for which the following is true + * - M is not marked Private + * - If M has a unique symbol, it does not appear in `prevDenots`. + * - M's signature as seen from prefix `pre` does not appear in `ownDenots` + * Return the denotation as seen from `pre`. + * Called from SymDenotations.computeMember. There, `ownDenots` are the denotations found in + * the base class, which shadow any inherited denotations with the same signature. + * `prevDenots` are the denotations that are defined in the class or inherited from + * a base type which comes earlier in the linearization. + */ + def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(implicit ctx: Context): PreDenotation + + /** Keep only those denotations in this group whose flags do not intersect + * with `excluded`. + */ + def filterExcluded(excluded: FlagSet)(implicit ctx: Context): PreDenotation + + private[this] var cachedPrefix: Type = _ + private[this] var cachedAsSeenFrom: AsSeenFromResult = _ + private[this] var validAsSeenFrom: Period = Nowhere + + type AsSeenFromResult <: PreDenotation + + /** The denotation with info(s) as seen from prefix type */ + final def asSeenFrom(pre: Type)(implicit ctx: Context): AsSeenFromResult = + if (Config.cacheAsSeenFrom) { + if ((cachedPrefix ne pre) || ctx.period != validAsSeenFrom) { + cachedAsSeenFrom = computeAsSeenFrom(pre) + cachedPrefix = pre + validAsSeenFrom = ctx.period + } + cachedAsSeenFrom + } else computeAsSeenFrom(pre) + + protected def computeAsSeenFrom(pre: Type)(implicit ctx: Context): AsSeenFromResult + + /** The union of two groups. */ + def union(that: PreDenotation): PreDenotation = + if (!this.exists) that + else if (!that.exists) this + else DenotUnion(this, that) + } + /** A denotation is the result of resolving * a name (either simple identifier or select) during a given period. * @@ -99,7 +171,9 @@ object Denotations { * * @param symbol The referencing symbol, or NoSymbol is none exists */ - abstract class Denotation(val symbol: Symbol) extends util.DotClass with printing.Showable { + abstract class Denotation(val symbol: Symbol) extends PreDenotation with printing.Showable { + + type AsSeenFromResult <: Denotation /** The type info of the denotation, exists only for non-overloaded denotations */ def info(implicit ctx: Context): Type @@ -121,6 +195,14 @@ object Denotations { /** Is this denotation overloaded? */ final def isOverloaded = isInstanceOf[MultiDenotation] + /** Denotation points to unique symbol; false for overloaded denotations + * and JointRef denotations. + */ + def hasUniqueSym: Boolean + + /** The name of the denotation */ + def name(implicit ctx: Context): Name + /** The signature of the denotation. */ def signature(implicit ctx: Context): Signature @@ -553,61 +635,19 @@ object Denotations { final def asSymDenotation = asInstanceOf[SymDenotation] def toText(printer: Printer): Text = printer.toText(this) - } - /** An overloaded denotation consisting of the alternatives of both given denotations. - */ - case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation(NoSymbol) { - final def infoOrCompleter = multiHasNot("info") - final def info(implicit ctx: Context) = infoOrCompleter - final def validFor = denot1.validFor & denot2.validFor - final def isType = false - final def signature(implicit ctx: Context) = Signature.OverloadedSignature - def atSignature(sig: Signature, site: Type, relaxed: Boolean)(implicit ctx: Context): Denotation = - if (sig eq Signature.OverloadedSignature) this - else derivedUnionDenotation(denot1.atSignature(sig, site, relaxed), denot2.atSignature(sig, site, relaxed)) - def current(implicit ctx: Context): Denotation = - derivedUnionDenotation(denot1.current, denot2.current) - def altsWith(p: Symbol => Boolean): List[SingleDenotation] = - denot1.altsWith(p) ++ denot2.altsWith(p) - def suchThat(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = { - val sd1 = denot1.suchThat(p) - val sd2 = denot2.suchThat(p) - if (sd1.exists) - if (sd2.exists) - if (isDoubleDef(denot1.symbol, denot2.symbol)) doubleDefError(denot1, denot2) - else throw new TypeError(i"failure to disambiguate overloaded reference at $this") - else sd1 - else sd2 - } - def hasAltWith(p: SingleDenotation => Boolean): Boolean = - denot1.hasAltWith(p) || denot2.hasAltWith(p) - def accessibleFrom(pre: Type, superAccess: Boolean)(implicit ctx: Context): Denotation = { - val d1 = denot1 accessibleFrom (pre, superAccess) - val d2 = denot2 accessibleFrom (pre, superAccess) - if (!d1.exists) d2 - else if (!d2.exists) d1 - else derivedUnionDenotation(d1, d2) - } - def mapInfo(f: Type => Type)(implicit ctx: Context): Denotation = - derivedUnionDenotation(denot1.mapInfo(f), denot2.mapInfo(f)) - def derivedUnionDenotation(d1: Denotation, d2: Denotation): Denotation = - if ((d1 eq denot1) && (d2 eq denot2)) this - else if (!d1.exists) d2 - else if (!d2.exists) d1 - else MultiDenotation(d1, d2) - override def toString = alternatives.mkString(" ") + // ------ PreDenotation ops ---------------------------------------------- - private def multiHasNot(op: String): Nothing = - throw new UnsupportedOperationException( - s"multi-denotation with alternatives $alternatives does not implement operation $op") + final def toDenot(pre: Type)(implicit ctx: Context): Denotation = this + final def containsSym(sym: Symbol): Boolean = hasUniqueSym && (symbol eq sym) } /** A non-overloaded denotation */ - abstract class SingleDenotation(symbol: Symbol) extends Denotation(symbol) with PreDenotation { - def hasUniqueSym: Boolean + abstract class SingleDenotation(symbol: Symbol) extends Denotation(symbol) { protected def newLikeThis(symbol: Symbol, info: Type): SingleDenotation + final def name(implicit ctx: Context): Name = symbol.name + final def signature(implicit ctx: Context): Signature = if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation else info match { @@ -979,13 +1019,13 @@ object Denotations { final def first = this final def last = this - final def toDenot(pre: Type)(implicit ctx: Context): Denotation = this - final def containsSym(sym: Symbol): Boolean = hasUniqueSym && (symbol eq sym) + final def matches(other: SingleDenotation)(implicit ctx: Context): Boolean = { val d = signature.matchDegree(other.signature) d == Signature.FullMatch || d >= Signature.ParamMatch && info.matches(other.info) } + final def filterWithPredicate(p: SingleDenotation => Boolean): SingleDenotation = if (p(this)) this else NoDenotation final def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): SingleDenotation = @@ -1080,105 +1120,92 @@ object Denotations { denot2.info, denot2.info) } - // --------------- PreDenotations ------------------------------------------------- - - /** A PreDenotation represents a group of single denotations - * It is used as an optimization to avoid forming MultiDenotations too eagerly. - */ - trait PreDenotation { - - /** A denotation in the group exists */ - def exists: Boolean - - /** First/last denotation in the group */ - def first: Denotation - def last: Denotation - - /** Convert to full denotation by &-ing all elements */ - def toDenot(pre: Type)(implicit ctx: Context): Denotation - - /** Group contains a denotation that refers to given symbol */ - def containsSym(sym: Symbol): Boolean - - /** Group contains a denotation with given signature */ - def matches(other: SingleDenotation)(implicit ctx: Context): Boolean - - /** Keep only those denotations in this group which satisfy predicate `p`. */ - def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation - - /** Keep only those denotations in this group which have a signature - * that's not already defined by `denots`. - */ - def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation - - /** Keep only those inherited members M of this predenotation for which the following is true - * - M is not marked Private - * - If M has a unique symbol, it does not appear in `prevDenots`. - * - M's signature as seen from prefix `pre` does not appear in `ownDenots` - * Return the denotation as seen from `pre`. - * Called from SymDenotations.computeMember. There, `ownDenots` are the denotations found in - * the base class, which shadow any inherited denotations with the same signature. - * `prevDenots` are the denotations that are defined in the class or inherited from - * a base type which comes earlier in the linearization. - */ - def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(implicit ctx: Context): PreDenotation - - /** Keep only those denotations in this group whose flags do not intersect - * with `excluded`. - */ - def filterExcluded(excluded: FlagSet)(implicit ctx: Context): PreDenotation - - private[this] var cachedPrefix: Type = _ - private[this] var cachedAsSeenFrom: AsSeenFromResult = _ - private[this] var validAsSeenFrom: Period = Nowhere - type AsSeenFromResult <: PreDenotation - - /** The denotation with info(s) as seen from prefix type */ - final def asSeenFrom(pre: Type)(implicit ctx: Context): AsSeenFromResult = - if (Config.cacheAsSeenFrom) { - if ((cachedPrefix ne pre) || ctx.period != validAsSeenFrom) { - cachedAsSeenFrom = computeAsSeenFrom(pre) - cachedPrefix = pre - validAsSeenFrom = ctx.period - } - cachedAsSeenFrom - } else computeAsSeenFrom(pre) + // --- Overloaded denotations and predenotations ------------------------------------------------- - protected def computeAsSeenFrom(pre: Type)(implicit ctx: Context): AsSeenFromResult + trait MultiPreDenotation extends PreDenotation { + def denot1: PreDenotation + def denot2: PreDenotation - /** The union of two groups. */ - def union(that: PreDenotation) = - if (!this.exists) that - else if (!that.exists) this - else DenotUnion(this, that) + assert(denot1.exists && denot2.exists, s"Union of non-existing denotations ($denot1) and ($denot2)") + def first = denot1.first + def last = denot2.last + def matches(other: SingleDenotation)(implicit ctx: Context): Boolean = + denot1.matches(other) || denot2.matches(other) + def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation = + derivedUnion(denot1 filterWithPredicate p, denot2 filterWithPredicate p) + def filterDisjoint(denot: PreDenotation)(implicit ctx: Context): PreDenotation = + derivedUnion(denot1 filterDisjoint denot, denot2 filterDisjoint denot) + def mapInherited(owndenot: PreDenotation, prevdenot: PreDenotation, pre: Type)(implicit ctx: Context): PreDenotation = + derivedUnion(denot1.mapInherited(owndenot, prevdenot, pre), denot2.mapInherited(owndenot, prevdenot, pre)) + def filterExcluded(excluded: FlagSet)(implicit ctx: Context): PreDenotation = + derivedUnion(denot1.filterExcluded(excluded), denot2.filterExcluded(excluded)) + protected def derivedUnion(denot1: PreDenotation, denot2: PreDenotation) = + if ((denot1 eq this.denot1) && (denot2 eq this.denot2)) this + else denot1 union denot2 } - final case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation { - assert(denots1.exists && denots2.exists, s"Union of non-existing denotations ($denots1) and ($denots2)") + final case class DenotUnion(denot1: PreDenotation, denot2: PreDenotation) extends MultiPreDenotation { def exists = true - def first = denots1.first - def last = denots2.last def toDenot(pre: Type)(implicit ctx: Context) = - (denots1 toDenot pre) & (denots2 toDenot pre, pre) + (denot1 toDenot pre) & (denot2 toDenot pre, pre) def containsSym(sym: Symbol) = - (denots1 containsSym sym) || (denots2 containsSym sym) - def matches(other: SingleDenotation)(implicit ctx: Context): Boolean = - denots1.matches(other) || denots2.matches(other) - def filterWithPredicate(p: SingleDenotation => Boolean): PreDenotation = - derivedUnion(denots1 filterWithPredicate p, denots2 filterWithPredicate p) - def filterDisjoint(denots: PreDenotation)(implicit ctx: Context): PreDenotation = - derivedUnion(denots1 filterDisjoint denots, denots2 filterDisjoint denots) - def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(implicit ctx: Context): PreDenotation = - derivedUnion(denots1.mapInherited(ownDenots, prevDenots, pre), denots2.mapInherited(ownDenots, prevDenots, pre)) - def filterExcluded(excluded: FlagSet)(implicit ctx: Context): PreDenotation = - derivedUnion(denots1.filterExcluded(excluded), denots2.filterExcluded(excluded)) - + (denot1 containsSym sym) || (denot2 containsSym sym) type AsSeenFromResult = PreDenotation - protected def computeAsSeenFrom(pre: Type)(implicit ctx: Context): PreDenotation = - derivedUnion(denots1.asSeenFrom(pre), denots2.asSeenFrom(pre)) - private def derivedUnion(denots1: PreDenotation, denots2: PreDenotation) = - if ((denots1 eq this.denots1) && (denots2 eq this.denots2)) this - else denots1 union denots2 + def computeAsSeenFrom(pre: Type)(implicit ctx: Context): PreDenotation = + derivedUnion(denot1.asSeenFrom(pre), denot2.asSeenFrom(pre)) + } + + /** An overloaded denotation consisting of the alternatives of both given denotations. + */ + case class MultiDenotation(denot1: Denotation, denot2: Denotation) extends Denotation(NoSymbol) with MultiPreDenotation { + final def infoOrCompleter = multiHasNot("info") + final def info(implicit ctx: Context) = infoOrCompleter + final def validFor = denot1.validFor & denot2.validFor + final def isType = false + final def hasUniqueSym = false + final def name(implicit ctx: Context) = denot1.name + final def signature(implicit ctx: Context) = Signature.OverloadedSignature + def atSignature(sig: Signature, site: Type, relaxed: Boolean)(implicit ctx: Context): Denotation = + if (sig eq Signature.OverloadedSignature) this + else derivedUnionDenotation(denot1.atSignature(sig, site, relaxed), denot2.atSignature(sig, site, relaxed)) + def current(implicit ctx: Context): Denotation = + derivedUnionDenotation(denot1.current, denot2.current) + def altsWith(p: Symbol => Boolean): List[SingleDenotation] = + denot1.altsWith(p) ++ denot2.altsWith(p) + def suchThat(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = { + val sd1 = denot1.suchThat(p) + val sd2 = denot2.suchThat(p) + if (sd1.exists) + if (sd2.exists) + if (isDoubleDef(denot1.symbol, denot2.symbol)) doubleDefError(denot1, denot2) + else throw new TypeError(i"failure to disambiguate overloaded reference at $this") + else sd1 + else sd2 + } + def hasAltWith(p: SingleDenotation => Boolean): Boolean = + denot1.hasAltWith(p) || denot2.hasAltWith(p) + def accessibleFrom(pre: Type, superAccess: Boolean)(implicit ctx: Context): Denotation = { + val d1 = denot1 accessibleFrom (pre, superAccess) + val d2 = denot2 accessibleFrom (pre, superAccess) + if (!d1.exists) d2 + else if (!d2.exists) d1 + else derivedUnionDenotation(d1, d2) + } + def mapInfo(f: Type => Type)(implicit ctx: Context): Denotation = + derivedUnionDenotation(denot1.mapInfo(f), denot2.mapInfo(f)) + def derivedUnionDenotation(d1: Denotation, d2: Denotation): Denotation = + if ((d1 eq denot1) && (d2 eq denot2)) this + else if (!d1.exists) d2 + else if (!d2.exists) d1 + else MultiDenotation(d1, d2) + type AsSeenFromResult = Denotation + def computeAsSeenFrom(pre: Type)(implicit ctx: Context): Denotation = + derivedUnionDenotation(denot1.asSeenFrom(pre), denot2.asSeenFrom(pre)) + override def toString = alternatives.mkString(" ") + + private def multiHasNot(op: String): Nothing = + throw new UnsupportedOperationException( + s"multi-denotation with alternatives $alternatives does not implement operation $op") } // --------------- Context Base Trait ------------------------------- From 7e327514a53a3d802c3df7ab1d3ddd1f54bb5f62 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 21:36:43 +0100 Subject: [PATCH 12/58] Handle shadowed refs under new scheme --- compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 9c1c7e0433d9..198917f5476e 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -187,8 +187,11 @@ trait TypeAssigner { // it could be that we found an inaccessible private member, but there is // an inherited non-private member with the same name and signature. val d2 = pre.nonPrivateMember(name) - if (reallyExists(d2) && firstTry && !config.Config.newScheme) - test(tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), false) + if (reallyExists(d2) && firstTry) + test( + if (config.Config.newScheme) TermRef.withDenot(pre, d2) + else tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), + false) else if (pre.derivesFrom(defn.DynamicClass)) { TryDynamicCallType } else { From d3b04aa28c187225a7d11e395e31bb85bf048dca Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 21:37:51 +0100 Subject: [PATCH 13/58] Refine Erasure#transform JoinRefDenotations before erasure become UniqueRefDenotations after. The former are no longer legal after erasure. --- compiler/src/dotty/tools/dotc/transform/Erasure.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 8b093a29a3fb..670fb2f47ac9 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -85,7 +85,10 @@ class Erasure extends Phase with DenotTransformer { ref.copySymDenotation(symbol = newSymbol, owner = newOwner, initFlags = newFlags, info = newInfo) } } - case ref => + case ref: JointRefDenotation => + new UniqueRefDenotation( + ref.symbol, transformInfo(ref.symbol, ref.symbol.info), ref.validFor) + case _ => ref.derivedSingleDenotation(ref.symbol, transformInfo(ref.symbol, ref.symbol.info)) } From c24785039f3b29c6b728613df2aaacb26b6c0ae3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 19 Nov 2017 21:39:25 +0100 Subject: [PATCH 14/58] Fixes to handling of overloaded references - need to adapt denotation if prefix changes in `withPrefix` - need to recover name of reference from the denotation. --- compiler/src/dotty/tools/dotc/core/Types.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 3abd464753df..595d2a4291be 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1548,7 +1548,11 @@ object Types { } final def name(implicit ctx: Context): ThisName = { - if (myName == null) myName = designator.asInstanceOf[Symbol].name.asInstanceOf[ThisName] + if (myName == null) { + val sym = designator.asInstanceOf[Symbol] + val d = if (sym.exists || lastDenotation == null) sym.denot else lastDenotation + myName = d.name.asInstanceOf[ThisName] + } myName } @@ -2031,7 +2035,9 @@ object Types { def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = designator match { case designator: TermSymbol @unchecked => - TermRef(prefix, designator) + val core = TermRef(prefix, designator) + if (isOverloaded && Config.newScheme) core.withDenot(denot.asSeenFrom(prefix)) + else core case _ => // If symbol exists, the new signature is the symbol's signature as seen // from the new prefix, modulo consistency From 7069e63e31f4bb4d66217247bc8b2cceeea8aefb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 20 Nov 2017 14:52:09 +0100 Subject: [PATCH 15/58] Bugfix in ensureAccessible --- compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 198917f5476e..68ed46735620 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -189,7 +189,7 @@ trait TypeAssigner { val d2 = pre.nonPrivateMember(name) if (reallyExists(d2) && firstTry) test( - if (config.Config.newScheme) TermRef.withDenot(pre, d2) + if (config.Config.newScheme) NamedType.withDenot(pre, d2) else tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { From 17606c9ca5fa63338c123c5d1e69cd583cc37162 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 20 Nov 2017 15:44:42 +0100 Subject: [PATCH 16/58] Better diagnostics for implicit shadowing errors - don't suppress them when retying after a contextual search - give a more helpful error message --- .../dotty/tools/dotc/typer/Implicits.scala | 36 ++++++++++++++----- tests/neg/implicit-shadowing.scala | 12 +++++++ 2 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 tests/neg/implicit-shadowing.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 254bca871396..961538e09cd7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -341,8 +341,14 @@ object Implicits { shadowing: Type, val expectedType: Type, val argument: Tree) extends SearchFailureType { + /** same as err.refStr but always prints owner even if it is a term */ + def show(ref: Type)(implicit ctx: Context) = ref match { + case ref: NamedType if ref.symbol.maybeOwner.isTerm => + i"${ref.symbol} in ${ref.symbol.owner}" + case _ => err.refStr(ref) + } def explanation(implicit ctx: Context): String = - em"${err.refStr(ref)} does $qualify but is shadowed by ${err.refStr(shadowing)}" + em"${show(ref)} does $qualify but it is shadowed by ${show(shadowing)}" } class DivergingImplicit(ref: TermRef, @@ -646,12 +652,18 @@ trait Implicits { self: Typer => case arg: Trees.SearchFailureIdent[_] => shortForm case _ => - i"""$headline. - |I found: - | - | ${arg.show.replace("\n", "\n ")} - | - |But ${arg.tpe.asInstanceOf[SearchFailureType].explanation}.""" + arg.tpe match { + case tpe: ShadowedImplicit => + i"""$headline; + |${tpe.explanation}.""" + case tpe: SearchFailureType => + i"""$headline. + |I found: + | + | ${arg.show.replace("\n", "\n ")} + | + |But $tpe.explanation}.""" + } } arg.tpe match { case ambi: AmbiguousImplicits => @@ -1020,7 +1032,15 @@ trait Implicits { self: Typer => searchImplicits(eligible, contextual).recoverWith { failure => failure.reason match { case _: AmbiguousImplicits => failure - case _ => if (contextual) bestImplicit(contextual = false) else failure + case reason => + if (contextual) + bestImplicit(contextual = false).recoverWith { + failure2 => reason match { + case (_: DivergingImplicit) | (_: ShadowedImplicit) => failure + case _ => failure2 + } + } + else failure } } } diff --git a/tests/neg/implicit-shadowing.scala b/tests/neg/implicit-shadowing.scala new file mode 100644 index 000000000000..ae33750eb72a --- /dev/null +++ b/tests/neg/implicit-shadowing.scala @@ -0,0 +1,12 @@ +object Test { + + class C + + def outer(implicit c: C) = { + + def f(c: C) = implicitly[C] // error: shadowing + def g(c: Int) = implicitly[C] // ok since type is different + + f(new C) + } +} From 0a471ee20712f714033c995811274b152a1ecfad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 20 Nov 2017 17:14:25 +0100 Subject: [PATCH 17/58] Improve "not found" message. Gave sometimes nonsensical messages like x is not a member of Object { ... } --- .../dotty/tools/dotc/reporting/diagnostic/messages.scala | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index eb2947893753..b1b0fcd1483e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -356,12 +356,7 @@ object messages { ) } - val siteType = site match { - case tp: NamedType => tp.info - case tp => tp - } - - ex"$selected `$name` is not a member of $siteType$closeMember" + ex"$selected `$name` is not a member of ${site.widen}$closeMember" } val explanation = "" From 5b6657d9618d5a107177df75c2b186ab214eac8f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 20 Nov 2017 17:16:13 +0100 Subject: [PATCH 18/58] Better error message for merge errors Made little sense when it was types that were merged. --- .../dotty/tools/dotc/core/Denotations.scala | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index e99a931676e3..5a205e48e21f 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1110,14 +1110,20 @@ object Denotations { val sym1 = denot1.symbol val sym2 = denot2.symbol def fromWhere = if (pre == NoPrefix) "" else i"\nwhen seen as members of $pre" - throw new MergeError( - i"""cannot merge - | $sym1: ${sym1.info} and - | $sym2: ${sym2.info}; - |they are both defined in ${sym1.owner} but have matching signatures - | ${denot1.info} and - | ${denot2.info}$fromWhere""", - denot2.info, denot2.info) + val msg = + if (denot1.isTerm) + i"""cannot merge + | $sym1: ${sym1.info} and + | $sym2: ${sym2.info}; + |they are both defined in ${sym1.owner} but have matching signatures + | ${denot1.info} and + | ${denot2.info}$fromWhere""" + else + i"""cannot merge + | $sym1 ${denot1.info} + | $sym2 ${denot2.info} + |they are conflicting definitions$fromWhere""" + throw new MergeError(msg, denot2.info, denot2.info) } // --- Overloaded denotations and predenotations ------------------------------------------------- From fc85a417e5b4f073a268f0ff6ff811042be8e1c4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 22 Nov 2017 16:52:16 +0100 Subject: [PATCH 19/58] Never change the symbol of a symbolic NamedType Symbolic NamedTypes are represented by their symbol, so the symbol should never change. This required a large-scale redesign. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +- .../dotty/tools/dotc/core/Denotations.scala | 2 +- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../dotty/tools/dotc/core/TypeErasure.scala | 6 +- .../src/dotty/tools/dotc/core/Types.scala | 447 +++++++++++++----- .../src/dotty/tools/dotc/core/Uniques.scala | 12 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 47 +- .../core/unpickleScala2/Scala2Unpickler.scala | 4 +- .../dotc/transform/ParamForwarding.scala | 2 +- .../tools/dotc/transform/PostTyper.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../tools/dotc/typer/ErrorReporting.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 5 +- 13 files changed, 369 insertions(+), 168 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index a622a75e6c53..d5f4d334a963 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -710,7 +710,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { if (sym.isType) { assert(!sym.is(TypeParam)) if (config.Config.newScheme) TypeRef.withSym(tree.tpe, sym.asType) - else TypeRef.applyOLD(tree.tpe, sym.name.asTypeName) + else TypeRef(tree.tpe, sym.name.asTypeName) } else TermRef(tree.tpe, sym.name.asTermName, sym.denot.asSeenFrom(tree.tpe)) @@ -722,7 +722,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { untpd.SelectWithSig(tree, name, sig) .withType( if (config.Config.newScheme) tree.tpe.select(name.asTermName, sig) - else TermRef.applyOLD(tree.tpe, name.asTermName.withSig(sig))) + else TermRef(tree.tpe, name.asTermName.withSig(sig))) /** A select node with selector name and signature taken from `sym`. * Note: Use this method instead of select(sym) if the referenced symbol diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 5a205e48e21f..07dc4b312ca2 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -1044,7 +1044,7 @@ object Denotations { case thisd: SymDenotation => thisd.owner case _ => if (symbol.exists) symbol.owner else NoSymbol } - if (!owner.membersNeedAsSeenFrom(pre)) this + if (!owner.membersNeedAsSeenFrom(pre) || symbol.is(NonMember)) this else derivedSingleDenotation(symbol, symbol.info.asSeenFrom(pre, owner)) } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index ed4dce6bf292..3b63a2dc9a2a 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -310,7 +310,7 @@ trait Symbols { this: Context => /** Create a new skolem symbol. This is not the same as SkolemType, even though the * motivation (create a singleton referencing to a type) is similar. */ - def newSkolem(tp: Type) = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | Permanent, tp) + def newSkolem(tp: Type) = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | NonMember | Permanent, tp) def newErrorSymbol(owner: Symbol, name: Name, msg: => Message) = { val errType = ErrorType(msg) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 43acca10a1d1..b62327f8b103 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -86,6 +86,7 @@ object TypeErasure { object ErasedValueType { def apply(tycon: TypeRef, erasedUnderlying: Type)(implicit ctx: Context) = { + assert(erasedUnderlying.exists) unique(new CachedErasedValueType(tycon, erasedUnderlying)) } } @@ -506,7 +507,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean private def sigName(tp: Type)(implicit ctx: Context): TypeName = try { tp match { case tp: TypeRef => - if (!tp.denot.exists) throw new MissingType(tp.prefix, tp.name) + if (!tp.denot.exists) { + // println(i"missing: ${tp.toString} ${tp.denot} / ${tp.prefix.member(tp.name)}") + throw new MissingType(tp.prefix, tp.name) + } val sym = tp.symbol if (!sym.isClass) { val info = tp.info diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 595d2a4291be..f2dabe27b91e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1134,26 +1134,24 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = - if (Config.newScheme) NamedType.withDenot(this, member(name)).reduceProjection - else NamedType.applyOLD(this, name).reduceProjection - - def select(name: TermName)(implicit ctx: Context): TermRef = - if (Config.newScheme) TermRef.withDenot(this, member(name)) - else TermRef.applyOLD(this, name) - - def select(name: TermName, sig: Signature)(implicit ctx: Context): TermRef = { - assert(Config.newScheme) - TermRef.withDenot(this, member(name).atSignature(sig)) - } + if (Config.newScheme) NamedType(this, name, member(name)).reduceProjection + else NamedType(this, name).reduceProjection /** The type , reduced if possible, with given denotation if unreduced */ def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = // ### drop name - NamedType.apply(this, name, denot).reduceProjection + NamedType(this, name, denot).reduceProjection /** The type with either `sym` or its signed name as designator, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = NamedType.withSym(this, sym).reduceProjection + def select(name: TermName)(implicit ctx: Context): TermRef = + if (Config.newScheme) TermRef(this, name, member(name)) + else TermRef(this, name) + + def select(name: TermName, sig: Signature)(implicit ctx: Context): TermRef = + TermRef(this, name, member(name).atSignature(sig)) + // ----- Access to parts -------------------------------------------- /** The normalized prefix of this type is: @@ -1510,6 +1508,174 @@ object Types { type NameSpace = TypeRef /* | Null */ @sharable val noNameSpace: NameSpace = null + trait NamedTypeNEW extends NamedType { self => + + override def name(implicit ctx: Context) = designator match { + case name: Name => name.asInstanceOf[ThisName] + case sym: Symbol => sym.name.asInstanceOf[ThisName] + } + + override def symbol(implicit ctx: Context): Symbol = designator match { + case sym: Symbol => sym + case _ => (if (denotationIsCurrent) lastDenotation else denot).symbol + } + + /** If the reference is symbolic or the denotation is current, its symbol, otherwise NoDenotation. + * + * Note: This operation does not force the denotation, and is therefore + * timing dependent. It should only be used if the outcome of the + * essential computation does not depend on the symbol being present or not. + * It's currently used to take an optimized path in substituters and + * type accumulators, as well as to be safe in diagnostic printing. + * Normally, it's better to use `symbol`, not `currentSymbol`. + */ + override def currentSymbol(implicit ctx: Context) = designator match { + case sym: Symbol => sym + case _ => if (denotationIsCurrent) lastDenotation.symbol else NoSymbol + } + + override protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = + currentSymbol // ### todo: drop + + private def lastKnownSymbol = + if (lastDenotation != null) lastDenotation.symbol else NoSymbol + + override protected def computeDenot(implicit ctx: Context): Denotation = { + def finish(d: Denotation) = { + if (ctx.typerState.ephemeral) + record("ephemeral cache miss: loadDenot") + else if (d.exists) + // Avoid storing NoDenotations in the cache - we will not be able to recover from + // them. The situation might arise that a type has NoDenotation in some later + // phase but a defined denotation earlier (e.g. a TypeRef to an abstract type + // is undefined after erasure.) We need to be able to do time travel back and + // forth also in these cases. + setDenot(d) + d + } + val savedEphemeral = ctx.typerState.ephemeral + ctx.typerState.ephemeral = false + try { + designator match { + case sym: Symbol => + if (sym.isValidInCurrentRun) { + val lastd = lastDenotation + if (lastd == null) + finish(sym.asSeenFrom(prefix)) + else if (lastd.validFor.runId == ctx.runId || lastd.isInstanceOf[SymDenotation]) + finish(lastd.current) + else + finish(loadDenot(sym.name, sym)) + } + else finish(loadDenot(sym.name, sym)) + case name: Name => + finish(loadDenot(name, lastKnownSymbol)) + } + } + finally ctx.typerState.ephemeral |= savedEphemeral + } + + private def loadDenot(name: Name, lastSym: Symbol)(implicit ctx: Context): Denotation = { + val d = memberDenot(prefix, name, !lastSym.exists || lastSym.is(Private)) + if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) { + // name has changed; try load in earlier phase and make current + val d = loadDenot(name, lastSym)(ctx.withPhase(ctx.phaseId - 1)).current + if (d.exists) d + else throw new Error(s"failure to reload $this of class $getClass") + } + else if (d.isOverloaded && lastDenotation != null) + d.atSignature(lastDenotation.signature) + else d + } + + protected def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = + if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) + + override def checkDenot()(implicit ctx: Context) = { + if (name.toString == "TT" && false) { + println(i"$toString gets denot $lastDenotation, hash = $hash") + assert(lastDenotation.exists) + } + } + + protected[dotc] override def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { + lastDenotation = denot + checkedPeriod = ctx.period + checkDenot() + } + + protected[dotc] override def withSym(sym: Symbol)(implicit ctx: Context): ThisType = designator match { + case desig: Symbol if desig ne sym => NamedType(prefix, sym).asInstanceOf[ThisType] + case _ => this + } + + override protected[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = + if (denot.exists) { + val adapted = withSym(denot.symbol) + if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] + else { + setDenot(denot) + this + } + } + else this + + /** Create a NamedType of the same kind as this type, but with a new prefix. + */ + override def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { + def reload(name: Name, lastSym: Symbol): NamedType = { + val allowPrivate = !lastSym.exists || lastSym.is(Private) && prefix.classSymbol == this.prefix.classSymbol + var d = memberDenot(prefix, name, allowPrivate) + if (d.isOverloaded && lastSym.exists) + d = d.atSignature( + if (lastSym.signature == Signature.NotAMethod) Signature.NotAMethod + else lastSym.asSeenFrom(prefix).signature) + NamedType(prefix, name, d) + } + val res = designator match { + case sym: Symbol => + if (!sym.owner.membersNeedAsSeenFrom(prefix) || sym.is(NonMember)) + NamedType(prefix, sym) + else { + // NamedType(prefix, sym.name, + // sym.derivedSingleDenotation(sym, sym.asClass.classInfo.derivedClassInfo(prefix))) + val candidate = reload(sym.name, sym) + val falseOverride = sym.isClass && candidate.symbol.exists && candidate.symbol != symbol + // A false override happens if we rebind an inner class to another type with the same name + // in an outer subclass. This is wrong, since classes do not override. We need to + // return a type with the existing class info as seen from the new prefix instead. + if (falseOverride) NamedType(prefix, sym.name, denot.asSeenFrom(prefix)) + else candidate + } + case name: Name => + reload(name, lastKnownSymbol) + } + //if (name.toString == "TT") println(i"$this withPrefix $prefix = $res") + res + } + } + + trait TermRefNEW extends TermRef with NamedTypeNEW { + + override def alternatives(implicit ctx: Context): List[TermRef] = + denot.alternatives.map(withDenot(_)) + + override def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = + denot.altsWith(p).map(withDenot(_)) + } + + trait TypeRefNEW extends TypeRef with NamedTypeNEW + + final class CachedTermRefNEW(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) with TermRefNEW { + assert((prefix ne NoPrefix) || hasFixedSym) + myHash = hc + } + + final class CachedTypeRefNEW(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) with TypeRefNEW { + assert((prefix ne NoPrefix) || hasFixedSym) + myHash = hc + } + /** A NamedType of the form Prefix # name */ abstract class NamedType extends CachedProxyType with ValueType { self => @@ -1530,6 +1696,7 @@ object Types { private[this] var myNameSpace: NameSpace = noNameSpace private[dotc] def init()(implicit ctx: Context): this.type = { + assert(!Config.newScheme) def decompose(designator: Designator): Unit = designator match { case DerivedName(underlying, info: SignedName.SignedInfo) => mySig = info.sig @@ -1547,25 +1714,23 @@ object Types { this } - final def name(implicit ctx: Context): ThisName = { - if (myName == null) { - val sym = designator.asInstanceOf[Symbol] - val d = if (sym.exists || lastDenotation == null) sym.denot else lastDenotation - myName = d.name.asInstanceOf[ThisName] - } + def name(implicit ctx: Context): ThisName = { + assert(!Config.newScheme) + if (myName == null) + myName = designator.asInstanceOf[Symbol].name.asInstanceOf[ThisName] myName } - final override def signature(implicit ctx: Context): Signature = { + final override def signature(implicit ctx: Context): Signature = { // keep if (mySig == null) mySig = denot.signature mySig } final def nameSpace: NameSpace = myNameSpace - private[this] var lastDenotation: Denotation = _ + protected[this] var lastDenotation: Denotation = _ private[this] var lastSymbol: Symbol = _ - private[this] var checkedPeriod = Nowhere + protected[this] var checkedPeriod = Nowhere // Invariants: // (1) checkedPeriod != Nowhere => lastDenotation != null @@ -1586,8 +1751,10 @@ object Types { * type accumulators, as well as to be safe in diagnostic printing. * Normally, it's better to use `symbol`, not `currentSymbol`. */ - def currentSymbol(implicit ctx: Context) = + def currentSymbol(implicit ctx: Context) = { + assert(!Config.newScheme) if (denotationIsCurrent) symbol else NoSymbol + } /** The denotation currently denoted by this type */ final def denot(implicit ctx: Context): Denotation = { @@ -1607,8 +1774,10 @@ object Types { else computeDenot } + var prevDenotation: Denotation = _ + /** Hook for adding debug check code when denotations are assigned */ - final def checkDenot()(implicit ctx: Context) = { + def checkDenot()(implicit ctx: Context) = { if (Config.checkTypeRefCycles) lastDenotation match { case d: SingleDenotation => @@ -1632,30 +1801,53 @@ object Types { } /** A second fallback to recompute the denotation if necessary */ - private def computeDenot(implicit ctx: Context): Denotation = { + protected def computeDenot(implicit ctx: Context): Denotation = { + assert(!Config.newScheme) val savedEphemeral = ctx.typerState.ephemeral ctx.typerState.ephemeral = false try { + prevDenotation = lastDenotation + def finish(d: Denotation) = + if (ctx.typerState.ephemeral) { record("ephemeral cache miss: loadDenot"); d } + else if (d.exists) { + // Avoid storing NoDenotations in the cache - we will not be able to recover from + // them. The situation might arise that a type has NoDenotation in some later + // phase but a defined denotation earlier (e.g. a TypeRef to an abstract type + // is undefined after erasure.) We need to be able to do time travel back and + // forth also in these cases. + + // Don't use setDenot here; double binding checks can give spurious failures after erasure + if (name.toString == "Ops") + assert(lastSymbol == d.symbol, i"${lastSymbol.showLocated} != ${d.symbol.showLocated}") + lastDenotation = d + lastSymbol = d.symbol + checkedPeriod = ctx.period + checkDenot() + d + } + else d val d = lastDenotation match { case null => val sym = lastSymbol - if (sym != null && sym.isValidInCurrentRun && - (!Config.newScheme || - (prefix eq NoPrefix) || (prefix eq sym.owner.thisType) || sym.isReferencedSymbolically)) - denotOfSym(sym) - else loadDenot + if (sym != null && sym.isValidInCurrentRun) + if (!Config.newScheme || + (prefix eq NoPrefix) || (prefix eq sym.maybeOwner.thisType) || sym.isReferencedSymbolically) + finish(denotOfSym(sym)) + else if (Config.newScheme && sym.isClass) finish(denotOfSym(sym)) + else finish(loadDenot) + else finish(loadDenot) case d: SymDenotation => if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) if (hasFixedSym) - d.current + finish(d.current) else if (nameSpace != noNameSpace || d.exists && prefix.isTightPrefix(d.owner) || - d.isConstructor) d.current + d.isConstructor) finish(d.current) else - recomputeMember(d) // symbol could have been overridden, recompute membership + finish(recomputeMember(d)) // symbol could have been overridden, recompute membership else if (hasFixedSym && d.validFor == Nowhere) // denotation was invalidated - d.current - else try { + finish(d.current) + else finish(try { val newd = loadDenot // TODO: If symbolic re-enter in uniques map. if (newd.exists) newd else if (ctx.mode.is(Mode.Interactive)) d @@ -1669,24 +1861,10 @@ object Types { println(hasFixedSym) println(i"prefix = $prefix / ${prefix.member(name)}") throw ex - } + }) case d => - if (d.validFor.runId != ctx.period.runId) loadDenot - else d.current - } - if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot") - else if (d.exists) { - // Avoid storing NoDenotations in the cache - we will not be able to recover from - // them. The situation might arise that a type has NoDenotation in some later - // phase but a defined denotation earlier (e.g. a TypeRef to an abstract type - // is undefined after erasure.) We need to be able to do time travel back and - // forth also in these cases. - - // Don't use setDenot here; double binding checks can give spurious failures after erasure - lastDenotation = d - lastSymbol = d.symbol - checkedPeriod = ctx.period - checkDenot() + if (d.validFor.runId != ctx.period.runId) finish(loadDenot) + else finish(d.current) } d } @@ -1694,7 +1872,8 @@ object Types { } /** A member of `prefix` (disambiguated by `d.signature`) or, if none was found, `d.current`. */ - private def recomputeMember(d: SymDenotation)(implicit ctx: Context): Denotation = + private def recomputeMember(d: SymDenotation)(implicit ctx: Context): Denotation = { + assert(!Config.newScheme) asMemberOf(prefix, allowPrivate = d.is(Private)) match { case NoDenotation => d.current case newd: SingleDenotation => newd @@ -1704,14 +1883,17 @@ object Types { case _ => d.current } } + } - private def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = { + protected def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = { + assert(!Config.newScheme) val d = sym.denot val owner = d.owner if (owner.isTerm) d else d.asSeenFrom(prefix) } private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = { + assert(!Config.newScheme) def selfTypeOf(sym: Symbol) = if (sym.isClass) sym.asClass.givenSelfType else NoType assert( @@ -1745,10 +1927,12 @@ object Types { |period = ${ctx.phase} at run ${ctx.runId}""") } - private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { + protected[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { + assert(!Config.newScheme) val adapted = if (hasFixedSym) - this + if (Config.newScheme) withSym(denot.symbol) + else this else if (signature != denot.signature) withSig(denot.signature) else if (denot.symbol.isPrivate) { @@ -1764,7 +1948,8 @@ object Types { } } - private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { + protected[dotc] def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { + assert(!Config.newScheme) if (Config.checkNoDoubleBindings) if (ctx.settings.YnoDoubleBindings.value) checkSymAssign(denot.symbol) @@ -1777,12 +1962,14 @@ object Types { checkedPeriod = Nowhere } - private[dotc] def withSym(sym: Symbol)(implicit ctx: Context): this.type = { - setSym(sym) - this - } + protected[dotc] def withSym(sym: Symbol)(implicit ctx: Context): ThisType = { + assert(!Config.newScheme) + setSym(sym) + this + } private[dotc] final def setSym(sym: Symbol)(implicit ctx: Context): Unit = { + assert(!Config.newScheme) if (Config.checkNoDoubleBindings) if (ctx.settings.YnoDoubleBindings.value) checkSymAssign(sym) @@ -1790,6 +1977,7 @@ object Types { } private[dotc] final def uncheckedSetSym(sym: Symbol): Unit = { + assert(!Config.newScheme) lastDenotation = null lastSymbol = sym checkedPeriod = Nowhere @@ -1797,11 +1985,13 @@ object Types { private def withSig(sig: Signature)(implicit ctx: Context): NamedType = { assert(!Config.newScheme) - TermRef.applyOLD(prefix, designator.withSig(sig)) + TermRef(prefix, designator.withSig(sig)) } - protected def loadDenot(implicit ctx: Context): Denotation = { - val d = asMemberOf(prefix, allowPrivate = Config.newScheme && hasFixedSym) + private def loadDenot(implicit ctx: Context): Denotation = { + assert(!Config.newScheme) + val d = asMemberOf(prefix, allowPrivate = + Config.newScheme && lastSymbol != null && lastSymbol.is(Private)) def atSig(sig: Signature): Denotation = if (sig.ne(Signature.OverloadedSignature)) d.atSignature(sig).checkUnique else d @@ -1824,12 +2014,17 @@ object Types { } } - def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) + def reloadDenot()(implicit ctx: Context) = { + assert(!Config.newScheme) + setDenot(loadDenot) + } - protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = + protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { + assert(!Config.newScheme) if (nameSpace != noNameSpace) nameSpace.findMember(name, prefix, EmptyFlags) else if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) + } /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. @@ -1845,20 +2040,24 @@ object Types { } else this - def symbol(implicit ctx: Context): Symbol = + def symbol(implicit ctx: Context): Symbol = { + assert(!Config.newScheme) if (checkedPeriod == ctx.period || lastDenotation == null && lastSymbol != null && lastSymbol.isValidInCurrentRun) lastSymbol else denot.symbol + } /** Retrieves currently valid symbol without necessarily updating denotation. * Assumes that symbols do not change between periods in the same run. * Used to get the class underlying a ThisType. */ - private[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = + protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { + assert(!Config.newScheme) if (checkedPeriod.runId == ctx.runId) lastSymbol else symbol + } def info(implicit ctx: Context): Type = denot.info @@ -1978,7 +2177,7 @@ object Types { */ def withNameSpaceOLD(nameSpace: NameSpace)(implicit ctx: Context): NamedType = if (nameSpace == this.nameSpace) this - else NamedType.applyOLD(prefix, designator.withNameSpace(nameSpace)) + else NamedType(prefix, designator.withNameSpace(nameSpace)) override def equals(that: Any) = that match { case that: NamedType => @@ -2015,18 +2214,24 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded - private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - if (Config.newScheme) TermRef.withDenot(prefix, sd) - else TermRef.apply(prefix, name, sd) + private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = { + assert(!Config.newScheme) + TermRef.apply(prefix, name, sd) + } - def alternatives(implicit ctx: Context): List[TermRef] = + def alternatives(implicit ctx: Context): List[TermRef] = { + assert(!Config.newScheme) denot.alternatives map rewrap + } - def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = + def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = { + assert(!Config.newScheme) denot.altsWith(p) map rewrap + } private def fixDenot(candidate: TermRef, prefix: Type)(implicit ctx: Context): TermRef = if (symbol.exists && !candidate.symbol.exists) { // recompute from previous symbol + assert(!Config.newScheme) val ownSym = symbol val newd = asMemberOf(prefix, allowPrivate = ownSym.is(Private)) candidate.withDenot(newd.suchThat(_.signature == ownSym.signature)) @@ -2035,10 +2240,10 @@ object Types { def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = designator match { case designator: TermSymbol @unchecked => - val core = TermRef(prefix, designator) - if (isOverloaded && Config.newScheme) core.withDenot(denot.asSeenFrom(prefix)) - else core + assert(!Config.newScheme) + TermRef(prefix, designator) case _ => + assert(!Config.newScheme) // If symbol exists, the new signature is the symbol's signature as seen // from the new prefix, modulo consistency val curSig = signature @@ -2054,7 +2259,7 @@ object Types { } else designator assert(!Config.newScheme) - fixDenot(TermRef.applyOLD(prefix, designator1), prefix) + fixDenot(TermRef(prefix, designator1), prefix) } } @@ -2065,9 +2270,10 @@ object Types { override def underlying(implicit ctx: Context): Type = info - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = - if (Config.newScheme) TypeRef(prefix, designator.asInstanceOf[TypeSymbol]) - else TypeRef.applyOLD(prefix, designator) + def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { + assert(!Config.newScheme) + TypeRef(prefix, designator) + } } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { @@ -2085,18 +2291,11 @@ object Types { if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) object NamedType { - def applyOLD(prefix: Type, designator: Designator)(implicit ctx: Context) = - if (designator.isType) TypeRef.applyOLD(prefix, designator.asType) - else TermRef.applyOLD(prefix, designator.asTerm) - def apply(prefix: Type, designator: Symbol)(implicit ctx: Context) = - if (designator.isType) TypeRef(prefix, designator.asType) - else TermRef(prefix, designator.asTerm) - def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context) = - if (denot.isTerm) TermRef.withDenot(prefix, denot) - else TypeRef.withDenot(prefix, denot) + def apply(prefix: Type, designator: Designator)(implicit ctx: Context) = + if (designator.isType) TypeRef.apply(prefix, designator.asType) + else TermRef.apply(prefix, designator.asTerm) def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = - if (Config.newScheme) withDenot(prefix, denot) - else if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) + if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) else TypeRef.apply(prefix, designator.asTypeName, denot) def withSym(prefix: Type, sym: Symbol)(implicit ctx: Context): NamedType = if (sym.isType) TypeRef.withSym(prefix, sym.asType) @@ -2109,37 +2308,35 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def applyOLD(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] - - def apply(prefix: Type, designator: Symbol)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] + def apply(prefix: Type, desig: TermDesignator)(implicit ctx: Context): TermRef = + ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = true).asInstanceOf[TermRef] /** Create term ref to given initial denotation, taking the signature * from the denotation if it is completed, or creating a term ref without * signature, if denotation is not yet completed. */ - def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { - if (Config.newScheme) withDenot(prefix, denot) - else if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) - else denot match { - case denot: SingleDenotation => - applyOLD(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) - case _ => applyOLD(prefix, name) - } - } withDenot denot - - def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TermRef = - apply(prefix, denot.symbol).withDenot(denot) + def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = + if (Config.newScheme) + apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot) + else { + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) + else denot match { + case denot: SingleDenotation => + apply(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) + case _ => apply(prefix, name) + } + } withDenot denot /** Create a term ref referring to given symbol with given name. * This is similar to TermRef(Type, Symbol), except: * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. * (2) the designator of the TermRef is either the symbol or its name & unforced signature. */ - def withSymOLD(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = + def withSymOLD(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = { + assert(!Config.newScheme) if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else applyOLD(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) + else apply(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) + } def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) @@ -2148,31 +2345,28 @@ object Types { object TypeRef { /** Create type ref with given prefix and name */ - def applyOLD(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] - - /** Create type ref with given prefix and name */ - def apply(prefix: Type, desig: Symbol)(implicit ctx: Context): TypeRef = + def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref with given name and initial denotation */ - def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = { - if (Config.newScheme) withDenot(prefix, denot) - else if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) - else applyOLD(prefix, name.localizeIfPrivate(denot.symbol)) - } withDenot denot - - def withDenot(prefix: Type, denot: Denotation)(implicit ctx: Context): TypeRef = - apply(prefix, denot.symbol).withDenot(denot) + def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = + if (Config.newScheme) + apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot) + else { + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) + else apply(prefix, name.localizeIfPrivate(denot.symbol)) + } withDenot denot /** Create a type ref referring to either a given symbol or its name. * This is similar to TypeRef(prefix, sym), except: * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. * (2) the designator of the TypeRef is either the symbol or its name */ - def withSymOLD(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = + def withSymOLD(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = { + assert(!Config.newScheme) if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else applyOLD(prefix, name.localizeIfPrivate(sym)).withSym(sym) + else apply(prefix, name.localizeIfPrivate(sym)).withSym(sym) + } def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) @@ -3521,8 +3715,7 @@ object Types { if (appliedRefCache == null) { val tref = if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef // ??? not always symbolicRef - else if (Config.newScheme) TypeRef.withDenot(prefix, clsDenot) - else TypeRef.apply(prefix, cls.name, clsDenot) + else TypeRef(prefix, cls.name, clsDenot) appliedRefCache = tref.appliedTo(cls.typeParams.map(_.typeRef)) } diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index da5ff8085638..bd5976fef84f 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -56,10 +56,14 @@ object Uniques { def enterIfNew(prefix: Type, designator: Designator, isTerm: Boolean)(implicit ctx: Context): NamedType = { val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) - def newType = { - if (isTerm) new CachedTermRef(prefix, designator.asInstanceOf[TermDesignator], h) - else new CachedTypeRef(prefix, designator.asInstanceOf[TypeDesignator], h) - }.init() + def newType = + if (Config.newScheme) + if (isTerm) new CachedTermRefNEW(prefix, designator.asInstanceOf[TermDesignator], h) + else new CachedTypeRefNEW(prefix, designator.asInstanceOf[TypeDesignator], h) + else { + if (isTerm) new CachedTermRef(prefix, designator.asInstanceOf[TermDesignator], h) + else new CachedTypeRef(prefix, designator.asInstanceOf[TypeDesignator], h) + }.init() if (h == NotCached) newType else { val r = findPrevious(h, prefix, designator) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index aefe43477c69..27a8001f3f7e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -225,21 +225,20 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi var sname = readName() val prefix = readType() val space = readType().asInstanceOf[TypeRef] - if (Config.newScheme) { - val d = sname match { - case SignedName(name, sig) => space.decl(name).atSignature(sig) - case name => space.decl(name) + if (Config.newScheme) + sname match { + case SignedName(name, sig) => + TermRef(prefix, name, space.decl(name).atSignature(sig)) + case name => + TermRef(prefix, name, space.decl(name)) } - assert(d.symbol.exists) - TermRef.withDenot(prefix, d) - } - else TermRef.applyOLD(prefix, sname.withNameSpace(space)) + else TermRef(prefix, sname.withNameSpace(space)) case TYPEREFin => val name = readName().toTypeName val prefix = readType() val space = readType().asInstanceOf[TypeRef] - if (Config.newScheme) TermRef.withDenot(prefix, space.decl(name)) - else TypeRef.applyOLD(prefix, name.withNameSpace(space)) + if (Config.newScheme) TypeRef(prefix, name, space.decl(name)) + else TypeRef(prefix, name.withNameSpace(space)) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -299,20 +298,20 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val name = readName().toTypeName if (Config.newScheme) { val prefix = readType() - TypeRef.withDenot(prefix, prefix.member(name)) + TypeRef(prefix, name, prefix.member(name)) } - else TypeRef.applyOLD(readType(), name) + else TypeRef(readType(), name) case TERMREF => val sname = readName() - if (Config.newScheme) { - val prefix = readType() - val d = sname match { - case SignedName(name, sig) => prefix.member(name).atSignature(sig) - case name => prefix.member(name) + val prefix = readType() + if (Config.newScheme) + sname match { + case SignedName(name, sig) => + TermRef(prefix, name, prefix.member(name).atSignature(sig)) + case name => + TermRef(prefix, name, prefix.member(name)) } - TermRef.withDenot(prefix, d) - } - else TermRef.applyOLD(readType(), sname) + else TermRef(prefix, sname) case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) case RECtype => @@ -364,7 +363,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val prefix = readType() val res = NamedType.withSym(prefix, sym) prefix match { - case prefix: ThisType if !Config.newScheme && (prefix.cls eq sym.owner) => res.withDenot(sym.denot) + case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot) // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala // the problem arises when a self type of a trait is a type parameter of the same trait. case _ => res @@ -744,8 +743,10 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val start = currentAddr val cls = ctx.owner.asClass val assumedSelfType = - if (cls.is(Module) && cls.owner.isClass && !Config.newScheme /*???*/) - TermRef.applyOLD(cls.owner.thisType, cls.name.sourceModuleName.localizeIfPrivate(cls)) + if (cls.is(Module) && cls.owner.isClass) + TermRef(cls.owner.thisType, + if (Config.newScheme) cls.name.sourceModuleName + else cls.name.sourceModuleName.localizeIfPrivate(cls)) else NoType cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index c33b05ae31c7..7e9290d3628d 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -703,7 +703,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val pre = readTypeRef() val sym = readDisambiguatedSymbolRef(_.info.isParameterless) if (config.Config.newScheme || isLocal(sym) || (pre eq NoPrefix)) pre select sym - else TermRef.applyOLD(pre, sym.name.asTermName) + else TermRef(pre, sym.name.asTermName) case SUPERtpe => val thistpe = readTypeRef() val supertpe = readTypeRef() @@ -734,7 +734,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (!config.Config.newScheme && sym.isClass && sym.is(Scala2x) && sym.owner.isClass && !sym.owner.is(Package)) // There can be multiple Scala2 inner classes with the same prefix and name; use a namespace // to pick a particular one. - TypeRef.applyOLD(pre, sym.name.asTypeName.withNameSpace(sym.owner.typeRef)) + TypeRef(pre, sym.name.asTypeName.withNameSpace(sym.owner.typeRef)) else if (config.Config.newScheme || isLocal(sym) || pre == NoPrefix) { val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre pre1 select sym diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 354e482343c6..443e74e52cc2 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -98,7 +98,7 @@ class ParamForwarding(thisPhase: DenotTransformer) { val newSig = tpe.prefix.memberInfo(tpe.symbol).signature if (newSig.eq(Signature.NotAMethod)) tree else tree.withType( - TermRef.applyOLD(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) + TermRef(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) .asInstanceOf[T] case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index c7b945923199..e098bb50a33e 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -87,7 +87,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tpe: TermRef if tpe.signature.isUnderDefined => assert(!config.Config.newScheme) typr.println(i"fixing $tree with type ${tree.tpe.widen.toString} with sig ${tpe.signature} to ${tpe.widen.signature}") - tree.withType(TermRef.applyOLD(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] + tree.withType(TermRef(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 799932f97bc8..fe484c5c8c83 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -78,7 +78,7 @@ object Checking { case _ => false }.getOrElse(TypeTree(tparam.paramRef)) val orderedArgs = if (hasNamedArg(args)) tparams.map(argNamed) else args - val bounds = tparams.map(_.paramInfoAsSeenFrom(tycon.tpe).bounds) + val bounds = tparams.map(_.paramInfoAsSeenFrom(tree.tpe).bounds) def instantiate(bound: Type, args: List[Type]) = HKTypeLambda.fromParams(tparams, bound).appliedTo(args) if (boundsCheck) checkBounds(orderedArgs, bounds, instantiate) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 0427b4c76a66..d24127c9aa01 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -100,7 +100,7 @@ object ErrorReporting { if (tree.tpe.widen.exists) i"${exprStr(tree)} does not take ${kind}parameters" else - i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString}" + i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString} at ${ctx.phase}" def patternConstrStr(tree: Tree): String = ??? diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 68ed46735620..ae0a297b2606 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -189,7 +189,7 @@ trait TypeAssigner { val d2 = pre.nonPrivateMember(name) if (reallyExists(d2) && firstTry) test( - if (config.Config.newScheme) NamedType.withDenot(pre, d2) + if (config.Config.newScheme) NamedType(pre, name, d2) else tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { @@ -211,8 +211,7 @@ trait TypeAssigner { else errorType(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos) } } - else - ctx.makePackageObjPrefixExplicit(tpe withDenot d) + else ctx.makePackageObjPrefixExplicit(tpe withDenot d) case _ => tpe } From 5e584a87c549a9bbce02e18877c2011fb8b66d72 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 23 Nov 2017 19:16:37 +0100 Subject: [PATCH 20/58] Fixes to the new scheme --- .../dotty/tools/dotc/core/Denotations.scala | 25 +-- .../src/dotty/tools/dotc/core/Symbols.scala | 7 +- .../src/dotty/tools/dotc/core/Types.scala | 162 ++++++++++++++---- 3 files changed, 151 insertions(+), 43 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 07dc4b312ca2..35f431393274 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -760,22 +760,27 @@ object Denotations { /** Invalidate all caches and fields that depend on base classes and their contents */ def invalidateInheritedInfo(): Unit = () + private def updateValidity()(implicit ctx: Context): this.type = { + assert(ctx.runId > validFor.runId || ctx.settings.YtestPickler.value, // mixing test pickler with debug printing can travel back in time + s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor") + var d: SingleDenotation = this + do { + d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId) + d.invalidateInheritedInfo() + d = d.nextInRun + } while (d ne this) + this + } + /** Move validity period of this denotation to a new run. Throw a StaleSymbol error * if denotation is no longer valid. */ private def bringForward()(implicit ctx: Context): SingleDenotation = this match { case denot: SymDenotation if ctx.stillValid(denot) || ctx.acceptStale(denot) => - assert(ctx.runId > validFor.runId || ctx.settings.YtestPickler.value, // mixing test pickler with debug printing can travel back in time - s"denotation $denot invalid in run ${ctx.runId}. ValidFor: $validFor") - var d: SingleDenotation = denot - do { - d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId) - d.invalidateInheritedInfo() - d = d.nextInRun - } while (d ne denot) - this + updateValidity() case _ => - if (coveredInterval.containsPhaseId(ctx.phaseId)) { + if (!symbol.exists) updateValidity() + else if (coveredInterval.containsPhaseId(ctx.phaseId)) { if (ctx.debug) ctx.traceInvalid(this) staleSymbolError } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 3b63a2dc9a2a..2ad5487961ea 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -451,8 +451,13 @@ object Symbols { pos.exists && defRunId == ctx.runId } + /** Is symbol valid in current run? */ final def isValidInCurrentRun(implicit ctx: Context): Boolean = - lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot) + (lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot)) && + (lastDenot.symbol eq this) + // the last condition is needed because overwritten package members keep + // denotations pointing to the new symbol, so the validity periods check out OK. + // But once a package member is overridden it is not longerr valid. /** Designator overrides */ final override def isTerm(implicit ctx: Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f2dabe27b91e..c4abd83a82cd 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1510,16 +1510,54 @@ object Types { trait NamedTypeNEW extends NamedType { self => - override def name(implicit ctx: Context) = designator match { - case name: Name => name.asInstanceOf[ThisName] - case sym: Symbol => sym.name.asInstanceOf[ThisName] + private[this] var myName: Name = null + private[this] var mySig: Signature = null + private[this] var lastSymbol: Symbol = null + + override def name(implicit ctx: Context): ThisName = { + if (myName == null) myName = computeName + myName.asInstanceOf[ThisName] } - override def symbol(implicit ctx: Context): Symbol = designator match { - case sym: Symbol => sym - case _ => (if (denotationIsCurrent) lastDenotation else denot).symbol + private def computeName: Name = designator match { + case name: Name => name + case sym: Symbol => sym.lastKnownDenotation.initial.name + } + + final override def signature(implicit ctx: Context): Signature = { + if (mySig == null) mySig = computeSignature + mySig + } + + def computeSignature(implicit ctx: Context): Signature = { + val lastd = lastDenotation + if (lastd != null) lastd.signature + else symbol.asSeenFrom(prefix).signature } + private def currentSignature(implicit ctx: Context): Signature = + if (mySig != null) mySig + else { + val lastd = lastDenotation + if (lastd != null) lastd.signature + else { + val sym = currentSymbol + if (sym.exists) sym.asSeenFrom(prefix).signature + else null + } + } + + override def symbol(implicit ctx: Context): Symbol = + if (checkedPeriod == ctx.period) lastSymbol else computeSymbol + + private def computeSymbol(implicit ctx: Context): Symbol = + designator match { + case sym: Symbol => + if (sym.isValidInCurrentRun) sym else denot.symbol + case name => + (if (denotationIsCurrent) lastDenotation else denot).symbol + } + /** If the reference is symbolic or the denotation is current, its symbol, otherwise NoDenotation. * * Note: This operation does not force the denotation, and is therefore @@ -1540,6 +1578,9 @@ object Types { private def lastKnownSymbol = if (lastDenotation != null) lastDenotation.symbol else NoSymbol + private def infoDependsOnPrefix(sym: Symbol, prefix: Type)(implicit ctx: Context): Boolean = + sym.maybeOwner.membersNeedAsSeenFrom(prefix) && !sym.is(NonMember) + override protected def computeDenot(implicit ctx: Context): Denotation = { def finish(d: Denotation) = { if (ctx.typerState.ephemeral) @@ -1553,54 +1594,79 @@ object Types { setDenot(d) d } + //def isStillValidSym(d: Denotation) = d match { + // case sym: SymDenotation => ctx.stillValid(sym) + // case _ => false + //} val savedEphemeral = ctx.typerState.ephemeral ctx.typerState.ephemeral = false - try { - designator match { + try { finish { + val now = { + val lastd = lastDenotation + if (lastd != null && lastd.validFor.runId == ctx.runId || lastd.isInstanceOf[SymDenotation]) + lastd.current + else designator match { + case name: Name => + loadDenot(name, lastSymbol) + case sym: Symbol => + if (infoDependsOnPrefix(sym, prefix)) loadDenot(sym.name, sym) + else sym.denot + } + }/* + val was = designator match { case sym: Symbol => + //if (sym.name.toString == "Long") + // println(i"compute denot of $sym at ${ctx.runId} ${sym.isValidInCurrentRun}") if (sym.isValidInCurrentRun) { val lastd = lastDenotation if (lastd == null) - finish(sym.asSeenFrom(prefix)) + (sym.asSeenFrom(prefix)) else if (lastd.validFor.runId == ctx.runId || lastd.isInstanceOf[SymDenotation]) - finish(lastd.current) + (lastd.current) else - finish(loadDenot(sym.name, sym)) + (loadDenot(sym.name, sym)) } - else finish(loadDenot(sym.name, sym)) + else (loadDenot(sym.name, sym)) case name: Name => - finish(loadDenot(name, lastKnownSymbol)) + (loadDenot(name, lastKnownSymbol)) } + if (now.symbol ne was.symbol) + println(s"""diff for computeDenot $toString, ${lastDenotation} ${checkedPeriod.runId} ${ctx.runId} + |was: $was + |now: $now""")*/ + now + } } finally ctx.typerState.ephemeral |= savedEphemeral } private def loadDenot(name: Name, lastSym: Symbol)(implicit ctx: Context): Denotation = { - val d = memberDenot(prefix, name, !lastSym.exists || lastSym.is(Private)) + var d = memberDenot(prefix, name, lastSym == null || !lastSym.exists || lastSym.is(Private)) if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) { // name has changed; try load in earlier phase and make current - val d = loadDenot(name, lastSym)(ctx.withPhase(ctx.phaseId - 1)).current - if (d.exists) d - else throw new Error(s"failure to reload $this of class $getClass") + d = loadDenot(name, lastSym)(ctx.withPhase(ctx.phaseId - 1)).current + } + if (d.isOverloaded) { + val sig = currentSignature + if (sig != null) d = d.atSignature(sig) } - else if (d.isOverloaded && lastDenotation != null) - d.atSignature(lastDenotation.signature) - else d + d } protected def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) - override def checkDenot()(implicit ctx: Context) = { - if (name.toString == "TT" && false) { - println(i"$toString gets denot $lastDenotation, hash = $hash") - assert(lastDenotation.exists) - } - } + override def checkDenot()(implicit ctx: Context) = {} protected[dotc] override def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { lastDenotation = denot + lastSymbol = denot.symbol checkedPeriod = ctx.period + designator match { + case sym: Symbol if designator ne lastSymbol => + designator = lastSymbol.asInstanceOf[Designator{ type ThisName = self.ThisName }] + case _ => + } checkDenot() } @@ -1623,6 +1689,33 @@ object Types { /** Create a NamedType of the same kind as this type, but with a new prefix. */ override def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { + val now = { + def reload(): NamedType = { + val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol + var d = memberDenot(prefix, name, allowPrivate) + if (d.isOverloaded && lastSymbol.exists) + d = d.atSignature( + if (lastSymbol.signature == Signature.NotAMethod) Signature.NotAMethod + else lastSymbol.asSeenFrom(prefix).signature) + NamedType(prefix, name, d) + } + if (lastDenotation == null) NamedType(prefix, designator) + else designator match { + case sym: Symbol => + if (infoDependsOnPrefix(sym, prefix)) { + val candidate = reload() + val falseOverride = sym.isClass && candidate.symbol.exists && candidate.symbol != symbol + // A false override happens if we rebind an inner class to another type with the same name + // in an outer subclass. This is wrong, since classes do not override. We need to + // return a type with the existing class info as seen from the new prefix instead. + if (falseOverride) NamedType(prefix, sym.name, denot.asSeenFrom(prefix)) + else candidate + } + else NamedType(prefix, sym) + case name: Name => reload() + } + }/* + val was = { def reload(name: Name, lastSym: Symbol): NamedType = { val allowPrivate = !lastSym.exists || lastSym.is(Private) && prefix.classSymbol == this.prefix.classSymbol var d = memberDenot(prefix, name, allowPrivate) @@ -1653,6 +1746,12 @@ object Types { //if (name.toString == "TT") println(i"$this withPrefix $prefix = $res") res } + if (now ne was) + println(s"""diff for withPrefix $toString, prefix = $prefix + |was: $was + |now: $now""")*/ + now + } } trait TermRefNEW extends TermRef with NamedTypeNEW { @@ -1683,7 +1782,8 @@ object Types { type ThisName <: Name val prefix: Type - val designator: Designator { type ThisName = self.ThisName } + def designator: Designator { type ThisName = self.ThisName } + def designator_=(d: Designator { type ThisName = self.ThisName }): Unit assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") @@ -1721,7 +1821,7 @@ object Types { myName } - final override def signature(implicit ctx: Context): Signature = { // keep + override def signature(implicit ctx: Context): Signature = { if (mySig == null) mySig = denot.signature mySig } @@ -1817,8 +1917,6 @@ object Types { // forth also in these cases. // Don't use setDenot here; double binding checks can give spurious failures after erasure - if (name.toString == "Ops") - assert(lastSymbol == d.symbol, i"${lastSymbol.showLocated} != ${d.symbol.showLocated}") lastDenotation = d lastSymbol = d.symbol checkedPeriod = ctx.period @@ -2201,7 +2299,7 @@ object Types { */ } - abstract case class TermRef(override val prefix: Type, designator: TermDesignator) extends NamedType with SingletonType { + abstract case class TermRef(override val prefix: Type, var designator: TermDesignator) extends NamedType with SingletonType { type ThisType = TermRef type ThisName = TermName @@ -2263,7 +2361,7 @@ object Types { } } - abstract case class TypeRef(override val prefix: Type, designator: TypeDesignator) extends NamedType { + abstract case class TypeRef(override val prefix: Type, var designator: TypeDesignator) extends NamedType { type ThisType = TypeRef type ThisName = TypeName From d42da029088e0e300328f262855198ded799be9a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 13:25:11 +0100 Subject: [PATCH 21/58] Commit to new scheme where symbols of symbolic references never change --- .../src/dotty/tools/dotc/core/Types.scala | 127 +++++------------- 1 file changed, 35 insertions(+), 92 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c4abd83a82cd..d03547079c2c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1150,7 +1150,7 @@ object Types { else TermRef(this, name) def select(name: TermName, sig: Signature)(implicit ctx: Context): TermRef = - TermRef(this, name, member(name).atSignature(sig)) + TermRef(this, name, member(name).atSignature(sig, relaxed = !ctx.erasedTypes)) // ----- Access to parts -------------------------------------------- @@ -1578,8 +1578,8 @@ object Types { private def lastKnownSymbol = if (lastDenotation != null) lastDenotation.symbol else NoSymbol - private def infoDependsOnPrefix(sym: Symbol, prefix: Type)(implicit ctx: Context): Boolean = - sym.maybeOwner.membersNeedAsSeenFrom(prefix) && !sym.is(NonMember) + private def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = + symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) override protected def computeDenot(implicit ctx: Context): Denotation = { def finish(d: Denotation) = { @@ -1594,61 +1594,40 @@ object Types { setDenot(d) d } - //def isStillValidSym(d: Denotation) = d match { - // case sym: SymDenotation => ctx.stillValid(sym) - // case _ => false - //} val savedEphemeral = ctx.typerState.ephemeral ctx.typerState.ephemeral = false - try { finish { - val now = { - val lastd = lastDenotation - if (lastd != null && lastd.validFor.runId == ctx.runId || lastd.isInstanceOf[SymDenotation]) - lastd.current - else designator match { - case name: Name => - loadDenot(name, lastSymbol) - case sym: Symbol => - if (infoDependsOnPrefix(sym, prefix)) loadDenot(sym.name, sym) - else sym.denot - } - }/* - val was = designator match { - case sym: Symbol => - //if (sym.name.toString == "Long") - // println(i"compute denot of $sym at ${ctx.runId} ${sym.isValidInCurrentRun}") - if (sym.isValidInCurrentRun) { - val lastd = lastDenotation - if (lastd == null) - (sym.asSeenFrom(prefix)) - else if (lastd.validFor.runId == ctx.runId || lastd.isInstanceOf[SymDenotation]) - (lastd.current) - else - (loadDenot(sym.name, sym)) + try + lastDenotation match { + case lastd: SingleDenotation => + if (lastd.validFor.runId == ctx.runId) finish(lastd.current) + else lastd match { + case lastd: SymDenotation => + if (ctx.stillValid(lastd)) finish(lastd.current) + else finish(loadDenot(lastd.name, lastd)) + } + case _ => + designator match { + case name: Name => + val symd = if (lastSymbol == null) NoDenotation else lastSymbol.denot + finish(loadDenot(name, symd)) + case sym: Symbol => + val symd = sym.denot + if (infoDependsOnPrefix(symd, prefix)) finish(loadDenot(sym.name, symd)) + else finish(symd) } - else (loadDenot(sym.name, sym)) - case name: Name => - (loadDenot(name, lastKnownSymbol)) } - if (now.symbol ne was.symbol) - println(s"""diff for computeDenot $toString, ${lastDenotation} ${checkedPeriod.runId} ${ctx.runId} - |was: $was - |now: $now""")*/ - now - } - } finally ctx.typerState.ephemeral |= savedEphemeral } - private def loadDenot(name: Name, lastSym: Symbol)(implicit ctx: Context): Denotation = { - var d = memberDenot(prefix, name, lastSym == null || !lastSym.exists || lastSym.is(Private)) + private def loadDenot(name: Name, lastd: SymDenotation)(implicit ctx: Context): Denotation = { + var d = memberDenot(prefix, name, !lastd.exists || lastd.is(Private)) if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) { // name has changed; try load in earlier phase and make current - d = loadDenot(name, lastSym)(ctx.withPhase(ctx.phaseId - 1)).current + d = loadDenot(name, lastd)(ctx.withPhase(ctx.phaseId - 1)).current } if (d.isOverloaded) { val sig = currentSignature - if (sig != null) d = d.atSignature(sig) + if (sig != null) d = d.atSignature(sig, relaxed = !ctx.erasedTypes) } d } @@ -1670,10 +1649,9 @@ object Types { checkDenot() } - protected[dotc] override def withSym(sym: Symbol)(implicit ctx: Context): ThisType = designator match { - case desig: Symbol if desig ne sym => NamedType(prefix, sym).asInstanceOf[ThisType] - case _ => this - } + protected[dotc] override def withSym(sym: Symbol)(implicit ctx: Context): ThisType = + if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] + else this override protected[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = if (denot.exists) { @@ -1684,19 +1662,21 @@ object Types { this } } - else this + else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala. + this /** Create a NamedType of the same kind as this type, but with a new prefix. */ override def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { - val now = { def reload(): NamedType = { val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol var d = memberDenot(prefix, name, allowPrivate) - if (d.isOverloaded && lastSymbol.exists) - d = d.atSignature( + if (d.isOverloaded && lastSymbol.exists) { + val targetSig = if (lastSymbol.signature == Signature.NotAMethod) Signature.NotAMethod - else lastSymbol.asSeenFrom(prefix).signature) + else lastSymbol.asSeenFrom(prefix).signature + d = d.atSignature(targetSig, relaxed = !ctx.erasedTypes) + } NamedType(prefix, name, d) } if (lastDenotation == null) NamedType(prefix, designator) @@ -1714,43 +1694,6 @@ object Types { else NamedType(prefix, sym) case name: Name => reload() } - }/* - val was = { - def reload(name: Name, lastSym: Symbol): NamedType = { - val allowPrivate = !lastSym.exists || lastSym.is(Private) && prefix.classSymbol == this.prefix.classSymbol - var d = memberDenot(prefix, name, allowPrivate) - if (d.isOverloaded && lastSym.exists) - d = d.atSignature( - if (lastSym.signature == Signature.NotAMethod) Signature.NotAMethod - else lastSym.asSeenFrom(prefix).signature) - NamedType(prefix, name, d) - } - val res = designator match { - case sym: Symbol => - if (!sym.owner.membersNeedAsSeenFrom(prefix) || sym.is(NonMember)) - NamedType(prefix, sym) - else { - // NamedType(prefix, sym.name, - // sym.derivedSingleDenotation(sym, sym.asClass.classInfo.derivedClassInfo(prefix))) - val candidate = reload(sym.name, sym) - val falseOverride = sym.isClass && candidate.symbol.exists && candidate.symbol != symbol - // A false override happens if we rebind an inner class to another type with the same name - // in an outer subclass. This is wrong, since classes do not override. We need to - // return a type with the existing class info as seen from the new prefix instead. - if (falseOverride) NamedType(prefix, sym.name, denot.asSeenFrom(prefix)) - else candidate - } - case name: Name => - reload(name, lastKnownSymbol) - } - //if (name.toString == "TT") println(i"$this withPrefix $prefix = $res") - res - } - if (now ne was) - println(s"""diff for withPrefix $toString, prefix = $prefix - |was: $was - |now: $now""")*/ - now } } From 6aa350a483e0f35f547e788fa811f81eddfc06a1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 13:25:39 +0100 Subject: [PATCH 22/58] Drop hack that hides stale package members --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 004f15ba4c9a..f27dcd299935 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1847,7 +1847,6 @@ object SymDenotations { 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 From 3d6368004afa819f76dcb326ad7576c9dc9dd41b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 13:26:40 +0100 Subject: [PATCH 23/58] Fix definition of Throwable Should be reloaded as other Java classes. Otherwise t8367, which defines a new version of Throwable fails. --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 026f3ceae6cf..6c4311b90322 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -510,7 +510,6 @@ class Definitions { lazy val IndexOutOfBoundsException = ctx.requiredClass("java.lang.IndexOutOfBoundsException") lazy val ClassClass = ctx.requiredClass("java.lang.Class") lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number") - lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable") lazy val ClassCastExceptionClass = ctx.requiredClass("java.lang.ClassCastException") lazy val ArithmeticExceptionClass = ctx.requiredClass("java.lang.ArithmeticException") lazy val ArithmeticExceptionClass_stringConstructor = ArithmeticExceptionClass.info.member(nme.CONSTRUCTOR).suchThat(_.info.firstParamTypes match { @@ -525,6 +524,8 @@ class Definitions { // in scalac modified to have Any as parent + lazy val ThrowableType: TypeRef = ctx.requiredClassRef("java.lang.Throwable") + def ThrowableClass(implicit ctx: Context) = ThrowableType.symbol.asClass lazy val SerializableType: TypeRef = ctx.requiredClassRef("scala.Serializable") def SerializableClass(implicit ctx: Context) = SerializableType.symbol.asClass lazy val StringBuilderType: TypeRef = ctx.requiredClassRef("scala.collection.mutable.StringBuilder") @@ -680,7 +681,6 @@ class Definitions { // Derived types def RepeatedParamType = RepeatedParamClass.typeRef - def ThrowableType = ThrowableClass.typeRef def ClassType(arg: Type)(implicit ctx: Context) = { val ctype = ClassClass.typeRef From a76e884814d545e2dd404d6fa2754f9a69d9e9dd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 15:09:34 +0100 Subject: [PATCH 24/58] Refine determination when denotations can be private Also, need to skip overrwitten denotations or they will be mispredicted as coming from previous runs. --- .../dotty/tools/dotc/core/Denotations.scala | 6 +++ .../src/dotty/tools/dotc/core/Types.scala | 51 +++++++++++++------ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 35f431393274..10972957dff7 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -801,6 +801,12 @@ object Denotations { p1 } + /** Skip any denotations that have been removed by an installAfter or that + * are otherwise undefined. + */ + def skipRemoved(implicit ctx: Context): SingleDenotation = + if (myValidFor.code <= 0) nextDefined else this + /** Produce a denotation that is valid for the given context. * Usually called when !(validFor contains ctx.period) * (even though this is not a precondition). diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d03547079c2c..7dd4f7e8b527 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1582,6 +1582,7 @@ object Types { symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) override protected def computeDenot(implicit ctx: Context): Denotation = { + def finish(d: Denotation) = { if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot") @@ -1594,36 +1595,56 @@ object Types { setDenot(d) d } + + def fromDesignator = designator match { + case name: Name => + val sym = lastSymbol + val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private) + finish(loadDenot(name, allowPrivate)) + case sym: Symbol => + val symd = sym.lastKnownDenotation + if (symd.validFor.runId != ctx.runId && !ctx.stillValid(symd)) + finish(loadDenot(symd.name, allowPrivate = false)) + else if (infoDependsOnPrefix(symd, prefix)) + finish(loadDenot(symd.name, allowPrivate = symd.is(Private))) + else + finish(symd.current) + } + val savedEphemeral = ctx.typerState.ephemeral ctx.typerState.ephemeral = false try lastDenotation match { - case lastd: SingleDenotation => + case lastd0: SingleDenotation => + val lastd = lastd0.skipRemoved if (lastd.validFor.runId == ctx.runId) finish(lastd.current) else lastd match { case lastd: SymDenotation => if (ctx.stillValid(lastd)) finish(lastd.current) - else finish(loadDenot(lastd.name, lastd)) - } - case _ => - designator match { - case name: Name => - val symd = if (lastSymbol == null) NoDenotation else lastSymbol.denot - finish(loadDenot(name, symd)) - case sym: Symbol => - val symd = sym.denot - if (infoDependsOnPrefix(symd, prefix)) finish(loadDenot(sym.name, symd)) - else finish(symd) + else + try finish(loadDenot(lastd.name, allowPrivate = false)) + catch { + case ex: AssertionError => + println(i"assertion failed while $this . $lastd . ${lastd.validFor} ${lastd.flagsUNSAFE}") + throw ex + } + case _ => + fromDesignator } + case _ => fromDesignator } finally ctx.typerState.ephemeral |= savedEphemeral } - private def loadDenot(name: Name, lastd: SymDenotation)(implicit ctx: Context): Denotation = { - var d = memberDenot(prefix, name, !lastd.exists || lastd.is(Private)) + private def loadDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { + var d = memberDenot(prefix, name, allowPrivate) + if (!d.exists) { + val d1 = memberDenot(prefix, name, true) + assert(!d1.exists, i"bad allow private $this $name $d1 at ${ctx.phase}") + } if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) { // name has changed; try load in earlier phase and make current - d = loadDenot(name, lastd)(ctx.withPhase(ctx.phaseId - 1)).current + d = loadDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current } if (d.isOverloaded) { val sig = currentSignature From f1d0dbefb4f5c380acb3df2bad767a397bb9947f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 16:16:41 +0100 Subject: [PATCH 25/58] Avoid stackoverflow in compileNeg --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7dd4f7e8b527..8af2ac4afa70 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2201,7 +2201,7 @@ object Types { else if (prefix.isBottomType) prefix else if (isType) { val res = - if (symbol.is(ClassTypeParam)) argForParam(prefix) + if (currentSymbol.is(ClassTypeParam)) argForParam(prefix) else prefix.lookupRefined(name) if (res.exists) res else if (Config.splitProjections) From b36363372deb879d6842fcc9df3ba5c76bcbc848 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 16:17:26 +0100 Subject: [PATCH 26/58] Remove special case in substSym --- compiler/src/dotty/tools/dotc/core/Substituters.scala | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index 776ac977b643..e78dd9a7bd86 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -110,10 +110,7 @@ trait Substituters { this: Context => var ts = to while (fs.nonEmpty) { if (fs.head eq sym) - return { - if (tp.hasFixedSym) NamedType(tp.prefix, ts.head) // ### why the different treatement of prefix? - else substSym(tp.prefix, from, to, theMap) select ts.head - } + return substSym(tp.prefix, from, to, theMap) select ts.head fs = fs.tail ts = ts.tail } From 89ec7d65796582ce44de1e2fc050808f5ddc587a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 16:17:44 +0100 Subject: [PATCH 27/58] Cleanup --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 8ae79347fc0f..cb99e87407c1 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -85,13 +85,8 @@ object Trees { * which implements copy-on-write. Another use-case is in method interpolateAndAdapt in Typer, * where we overwrite with a simplified version of the type itself. */ - private[dotc] def overwriteType(tpe: T) = { - if (this.isInstanceOf[Template[_]]) - tpe match { - case tpe: TermRef => assert(tpe.hasFixedSym , s"$this <--- $tpe") - } + private[dotc] def overwriteType(tpe: T) = myTpe = tpe - } /** The type of the tree. In case of an untyped tree, * an UnAssignedTypeException is thrown. (Overridden by empty trees) From 6b6523aee24f058ad871c764b293f8f78cb4192b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 17:02:57 +0100 Subject: [PATCH 28/58] Replace references to hasFixedSym --- .../dotty/tools/dotc/core/TypeComparer.scala | 20 +++++++++---------- .../src/dotty/tools/dotc/core/Types.scala | 7 +++++++ .../tools/dotc/transform/TreeChecker.scala | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index eec7130675e8..cf4a2b6b4fc0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -183,24 +183,24 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // However the original judgment should be true. case _ => } - val sym1 = - if (tp1.symbol.is(ModuleClass) && tp2.symbol.is(ModuleVal)) - // For convenience we want X$ <:< X.type - // This is safe because X$ self-type is X.type - tp1.symbol.companionModule - else - tp1.symbol - if ((sym1 ne NoSymbol) && (sym1 eq tp2.symbol)) + val sym2 = tp2.symbol + var sym1 = tp1.symbol + if (sym1.is(ModuleClass) && sym2.is(ModuleVal)) + // For convenience we want X$ <:< X.type + // This is safe because X$ self-type is X.type + sym1 = sym1.companionModule + if ((sym1 ne NoSymbol) && (sym1 eq sym2)) ctx.erasedTypes || sym1.isStaticOwner || isSubType(tp1.prefix, tp2.prefix) || thirdTryNamed(tp1, tp2) else ( (tp1.name eq tp2.name) + && tp1.isMemberRef + && tp2.isMemberRef && isSubType(tp1.prefix, tp2.prefix) && tp1.signature == tp2.signature - && !tp1.hasFixedSym - && !tp2.hasFixedSym + && !(sym1.isClass && sym2.isClass) // class types don't subtype each other ) || thirdTryNamed(tp1, tp2) case _ => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8af2ac4afa70..66e9b6967cd8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1581,6 +1581,11 @@ object Types { private def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) + override def isMemberRef(implicit ctx: Context) = designator match { + case sym: Symbol => infoDependsOnPrefix(sym, prefix) + case _ => true + } + override protected def computeDenot(implicit ctx: Context): Denotation = { def finish(d: Denotation) = { @@ -2088,6 +2093,8 @@ object Types { else prefix.nonPrivateMember(name) } + def isMemberRef(implicit ctx: Context) = !hasFixedSym + /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. * diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index bfd571a565fe..237bc2d2efad 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -321,7 +321,7 @@ class TreeChecker extends Phase with SymTransformer { val tpe = tree.typeOpt val sym = tree.symbol val symIsFixed = tpe match { - case tpe: TermRef => tpe.hasFixedSym + case tpe: TermRef => ctx.erasedTypes || !tpe.isMemberRef case _ => false } if (sym.exists && !sym.is(Private) && From c4f0a3e41b5c0aee5a2e8f0065398a4fbd394ac0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 18:09:56 +0100 Subject: [PATCH 29/58] Weaken post condition in FirstTransform The postcondition checks that qualifiers of Select trees have types that derive from the symbol's owner. But this fails for methods that are lambda-lifted to become static methods in the enclosing package. We refine the condition to allow this. Not clear why the condition did not trigger before. --- compiler/src/dotty/tools/dotc/transform/FirstTransform.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index e935da998cb1..a3e877a3c292 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -80,7 +80,10 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { tree match { case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists => - assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree") + assert( + qual.tpe.derivesFrom(tree.symbol.owner) || + tree.symbol.is(JavaStatic) && qual.tpe.derivesFrom(tree.symbol.enclosingClass), + i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree") case _: TypeTree => case _: Import | _: NamedArg | _: TypTree => assert(false, i"illegal tree: $tree") From da99504123cf0273d6c7e9441828a129562d0033 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 18:10:45 +0100 Subject: [PATCH 30/58] Always reload denotation with initial name of last symbol. Otherwise we risk trying to load with a mangled name. --- .../src/dotty/tools/dotc/core/Types.scala | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 66e9b6967cd8..374fd6509bbb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1609,9 +1609,9 @@ object Types { case sym: Symbol => val symd = sym.lastKnownDenotation if (symd.validFor.runId != ctx.runId && !ctx.stillValid(symd)) - finish(loadDenot(symd.name, allowPrivate = false)) + finish(loadDenot(symd.initial.name, allowPrivate = false)) else if (infoDependsOnPrefix(symd, prefix)) - finish(loadDenot(symd.name, allowPrivate = symd.is(Private))) + finish(loadDenot(symd.initial.name, allowPrivate = symd.is(Private))) else finish(symd.current) } @@ -1627,7 +1627,7 @@ object Types { case lastd: SymDenotation => if (ctx.stillValid(lastd)) finish(lastd.current) else - try finish(loadDenot(lastd.name, allowPrivate = false)) + try finish(loadDenot(lastd.initial.name, allowPrivate = false)) catch { case ex: AssertionError => println(i"assertion failed while $this . $lastd . ${lastd.validFor} ${lastd.flagsUNSAFE}") @@ -1647,23 +1647,36 @@ object Types { val d1 = memberDenot(prefix, name, true) assert(!d1.exists, i"bad allow private $this $name $d1 at ${ctx.phase}") } - if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) { + if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) // name has changed; try load in earlier phase and make current d = loadDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current - } - if (d.isOverloaded) { - val sig = currentSignature - if (sig != null) d = d.atSignature(sig, relaxed = !ctx.erasedTypes) - } + if (d.isOverloaded) + d = disambiguate(d) d } protected def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) + private def disambiguate(d: Denotation)(implicit ctx: Context): Denotation = { + val sig = currentSignature + //if (ctx.isAfterTyper) println(i"overloaded $this / $d / sig = $sig") + if (sig != null) + d.atSignature(sig, relaxed = !ctx.erasedTypes) match { + case d1: SingleDenotation => d1 + case d1 => + d1.atSignature(sig, relaxed = false) match { + case d2: SingleDenotation => d2 + case d2 => d2.suchThat(currentSymbol.eq).orElse(d2) + } + } + else d + } + override def checkDenot()(implicit ctx: Context) = {} protected[dotc] override def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { + if (ctx.isAfterTyper) assert(!denot.isOverloaded, this) lastDenotation = denot lastSymbol = denot.symbol checkedPeriod = ctx.period From 614daaa457c13ea395e2f6d953624938c189ba00 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 18:11:18 +0100 Subject: [PATCH 31/58] Avoid stale symbol errors via isStatic --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 2ad5487961ea..fc2dbd00bb36 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -502,7 +502,7 @@ object Symbols { /** Special cased here, because it may be used on naked symbols in substituters */ final def isStatic(implicit ctx: Context): Boolean = - lastDenot != null && denot.isStatic + lastDenot != null && lastDenot.initial.isStatic /** A unique, densely packed integer tag for each class symbol, -1 * for all other symbols. To save memory, this method From 1ad2157e53a0dc2144bc25ac814a72d00af5639d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 18:40:35 +0100 Subject: [PATCH 32/58] Refine bringForward bringForward can now jump from overridden toplevel symbols to overriding ones. It turned out this was needed for more advanced compilation scenarios as exhibited by tastyBootstrap. Also, optimize initial in the case where we are already on the initial denotation. --- .../dotty/tools/dotc/core/Denotations.scala | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 10972957dff7..bd8ddeddedfb 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -739,7 +739,7 @@ object Denotations { * of this run. */ def initial: SingleDenotation = - if (validFor == Nowhere) this + if (validFor.firstPhaseId <= 1) this else { var current = nextInRun while (current.validFor.code > this.myValidFor.code) current = current.nextInRun @@ -775,16 +775,21 @@ object Denotations { /** Move validity period of this denotation to a new run. Throw a StaleSymbol error * if denotation is no longer valid. */ - private def bringForward()(implicit ctx: Context): SingleDenotation = this match { - case denot: SymDenotation if ctx.stillValid(denot) || ctx.acceptStale(denot) => - updateValidity() - case _ => - if (!symbol.exists) updateValidity() - else if (coveredInterval.containsPhaseId(ctx.phaseId)) { - if (ctx.debug) ctx.traceInvalid(this) - staleSymbolError - } - else NoDenotation + private def bringForward()(implicit ctx: Context): SingleDenotation = { + this match { + case symd: SymDenotation => + if (ctx.stillValid(symd)) return updateValidity() + if (symd.owner.is(Package)) { + val newd = symd.owner.info.decls.lookup(symd.name) + if (newd.exists) return newd + } + if (ctx.acceptStale(symd)) return updateValidity() + case _ => + } + if (!symbol.exists) return updateValidity() + if (!coveredInterval.containsPhaseId(ctx.phaseId)) return NoDenotation + if (ctx.debug) ctx.traceInvalid(this) + staleSymbolError } /** The next defined denotation (following `nextInRun`) or an arbitrary From 18a16e9059d94b4c451d09acef244ddf2530035b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 24 Nov 2017 22:18:41 +0100 Subject: [PATCH 33/58] Fix pickling of refs to shadowed inner classes --- compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index fbb0a6347b26..0b81850154ed 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -156,7 +156,9 @@ class TreePickler(pickler: TastyPickler) { pickleNameAndSig(sym.name, tpe.signature) pickleType(tpe.prefix) } - if (sym.is(Flags.Private)) { + val isShadowedRef = + sym.isClass && tpe.prefix.member(sym.name).symbol != sym + if (sym.is(Flags.Private) || isShadowedRef) { writeByte(if (tpe.isType) TYPEREFin else TERMREFin) withLength { pickleCore() From 03d7e3fee653df2838641a1006acc84d373a4687 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 14:37:52 +0100 Subject: [PATCH 34/58] Allow -uniqid printing on the fly. --- compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 2 +- compiler/src/dotty/tools/dotc/printing/Printer.scala | 6 ++++++ compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 0898a5b7cc37..5df74c94ba62 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -237,7 +237,7 @@ class PlainPrinter(_ctx: Context) extends Printer { /** If -uniqid is set, the unique id of symbol, after a # */ protected def idString(sym: Symbol): String = - if (ctx.settings.uniqid.value) "#" + sym.id else "" + if (ctx.settings.uniqid.value || Printer.debugPrintUnique) "#" + sym.id else "" def nameString(sym: Symbol): String = simpleNameString(sym) + idString(sym) // + "<" + (if (sym.exists) sym.owner else "") + ">" diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index e163a83f3bc5..fc2e13abf44d 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -110,4 +110,10 @@ abstract class Printer { /** A plain printer without any embellishments */ def plain: Printer } +object Printer { + /** Debug hook; set to true if you want to see unique ids but cannot run with option + * -uniqid. A typical use case is for further exploration after a -Ytest-pickler failure. + */ + @sharable var debugPrintUnique: Boolean = false +} diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index bd90d9c0cce5..ddf7f946a68e 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -295,7 +295,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else treeText def idText(tree: untpd.Tree): Text = { - if (ctx.settings.uniqid.value && tree.hasType && tree.symbol.exists) s"#${tree.symbol.id}" else "" + if ((ctx.settings.uniqid.value || Printer.debugPrintUnique) && tree.hasType && tree.symbol.exists) s"#${tree.symbol.id}" else "" } def nameIdText(tree: untpd.NameTree): Text = { From 5b818c4e40c74c98d329fbd149db61aa7bcec8c2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 14:39:50 +0100 Subject: [PATCH 35/58] Revert implementation of stableInRunSymbol It did not do the same thing at all in the new scheme. --- compiler/src/dotty/tools/dotc/core/Types.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 374fd6509bbb..7fc3951f8fda 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1572,8 +1572,14 @@ object Types { case _ => if (denotationIsCurrent) lastDenotation.symbol else NoSymbol } - override protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = - currentSymbol // ### todo: drop + /** Retrieves currently valid symbol without necessarily updating denotation. + * Assumes that symbols do not change between periods in the same run. + * Used to get the class underlying a ThisType. + */ + override protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { + if (checkedPeriod.runId == ctx.runId) lastSymbol + else symbol + } private def lastKnownSymbol = if (lastDenotation != null) lastDenotation.symbol else NoSymbol From 4dea7de334ba4f05350fde4c92f21d5ff7a83d30 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 14:47:45 +0100 Subject: [PATCH 36/58] Allow for aut-updating of package members Previously, an overwritten package member always got the denotation of the new package, so package members always auto-updated, and we could not even detect that they were no longer valid. This is a problem because it means that TermRefs and TypeRefs pointing to overwritten members will not be updated. We now do something less sweeping. A call to `current` will invoke `bringForward` which will do the update if the `autoUpdatePackageMembers` config flag is set. After the call to `current` the old symbol will be considered valid, which is a potential problems because we then have two valid symbols pointing to the same denotations. So it would be best if we could set `autoUpdatePackageMembers = false`. --- compiler/src/dotty/tools/dotc/config/Config.scala | 5 +++++ compiler/src/dotty/tools/dotc/core/Denotations.scala | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index d7f5985177fb..bf88b4a762f8 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -144,6 +144,11 @@ object Config { */ final val simplifyApplications = true + /** If this flag is on, automatically being forward no-longer valid package members. + * If it is off, raise a StaleSymbol error instead. + */ + final val autoUpdatePackageMembers = true + /** If set, prints a trace of all symbol completions */ final val showCompletions = false diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index bd8ddeddedfb..cc8bb3a12759 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -779,7 +779,7 @@ object Denotations { this match { case symd: SymDenotation => if (ctx.stillValid(symd)) return updateValidity() - if (symd.owner.is(Package)) { + if (Config.autoUpdatePackageMembers && symd.owner.is(Package)) { val newd = symd.owner.info.decls.lookup(symd.name) if (newd.exists) return newd } From 37a76d37ed0b1c10ce43f0573d61736b93cfd07c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 14:49:44 +0100 Subject: [PATCH 37/58] Make isStatic force less. It's called in a lot of maps and forcing presents a risk of stale symbol errors. So we should force the minimum possible. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Symbols.scala | 4 ++++ compiler/src/dotty/tools/dotc/printing/Printer.scala | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f27dcd299935..bcb9e6f40c08 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -566,7 +566,7 @@ object SymDenotations { /** Is this denotation static (i.e. with no outer instance)? */ final def isStatic(implicit ctx: Context) = - (if (maybeOwner eq NoSymbol) isRoot else maybeOwner.isStaticOwner) || + (if (maybeOwner eq NoSymbol) isRoot else maybeOwner.originDenotation.isStaticOwner) || myFlags.is(JavaStatic) /** Is this a package class or module class that defines static symbols? */ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index fc2dbd00bb36..4a1fc005f306 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -439,6 +439,10 @@ object Symbols { newd } + /** The original denotation of this symbol, without forcing anything */ + final def originDenotation: SymDenotation = + lastDenot.initial + /** The last known denotation of this symbol, without going through `current` */ final def lastKnownDenotation: SymDenotation = lastDenot diff --git a/compiler/src/dotty/tools/dotc/printing/Printer.scala b/compiler/src/dotty/tools/dotc/printing/Printer.scala index fc2e13abf44d..e0794627425a 100644 --- a/compiler/src/dotty/tools/dotc/printing/Printer.scala +++ b/compiler/src/dotty/tools/dotc/printing/Printer.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package printing import core._ From 65b30a203fd1d5b2eb2bf4104ef2b1c19629af1b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 15:44:20 +0100 Subject: [PATCH 38/58] Add missing case in TypeComparer TypeArgRefs with equal prefix, classes and indices should compare as equal. Previously this probably was not detected because equal prefixes happened to be identical and then the `eq` case in isSubType would kick in. The problematic case happened when comparing `ParMapLike[]#` with itself except that one side had a Lazy(CC) where the other had a CC. It was in compileStdLib, in case you were wondering. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 8 +++++++- compiler/test/dotty/tools/dotc/CompilationTests.scala | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index cf4a2b6b4fc0..904b4fe1ad65 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -528,7 +528,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } compareExpr case tp2: TypeArgRef => - isSubType(tp1, tp2.underlying.loBound) || fourthTry(tp1, tp2) + def sameTypeArgRef = tp1 match { + case tp1: TypeArgRef => + tp1.clsRef == tp2.clsRef && tp1.idx == tp2.idx && tp1.prefix =:= tp2.prefix + case _ => + false + } + sameTypeArgRef || isSubType(tp1, tp2.underlying.loBound) || fourthTry(tp1, tp2) case tp2 @ TypeBounds(lo2, hi2) => def compareTypeBounds = tp1 match { case tp1 @ TypeBounds(lo1, hi1) => diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 8326468c5ffa..ca42d0d23f8e 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -32,8 +32,8 @@ class CompilationTests extends ParallelTesting { // Positive tests ------------------------------------------------------------ // @Test // enable to test compileStdLib separately with detailed stats - def compileStdLib: Unit = { - implicit val testGroup: TestGroup = TestGroup("compileStdLib") + def compileStdLibOnly: Unit = { + implicit val testGroup: TestGroup = TestGroup("compileStdLibOnly") compileList("compileStdLib", StdLibSources.whitelisted, scala2Mode.and("-migration", "-Yno-inline", "-Ydetailed-stats")) }.checkCompile() From 25af9f60dffb715bfa7d82bd7d9fa2acc54f2f82 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 15:44:50 +0100 Subject: [PATCH 39/58] Switch to new Scheme --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index bf88b4a762f8..545d10d5312e 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -185,5 +185,5 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - val newScheme = false + val newScheme = true } From 6dcfc636b2988b20f00d851ceeba784fe2ca1f09 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 25 Nov 2017 17:39:02 +0100 Subject: [PATCH 40/58] Move test to pending --- tests/{ => pending}/pos/t2405.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{ => pending}/pos/t2405.scala (96%) diff --git a/tests/pos/t2405.scala b/tests/pending/pos/t2405.scala similarity index 96% rename from tests/pos/t2405.scala rename to tests/pending/pos/t2405.scala index a4ac914fb803..71627a10bc60 100644 --- a/tests/pos/t2405.scala +++ b/tests/pending/pos/t2405.scala @@ -9,7 +9,7 @@ object Test1 { // Testing for the absense of shadowing #1. object Test2 { import A.{x => y} - val x = 2 + //val x = 2 implicitly[Int] } From 49b78c346d1b0b30e0ddcb3e6c2745587d70183a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 11:32:48 +0100 Subject: [PATCH 41/58] Fail on all stale references by default Update stale references only if -Yupdate-state is set, fail with a StaleSymbol error otherwise. This required some fixes to the way ScalaShadowing was treated. If we compile a ScalaShadowing (as is done in tasty-bootstrap) we need to also overwrite the mirrored symbol in the scala package. Otherwise we would get a stale reference when looking up the latter. --- compiler/src/dotty/tools/dotc/config/Config.scala | 5 ----- .../dotty/tools/dotc/config/ScalaSettings.scala | 1 + .../src/dotty/tools/dotc/core/Definitions.scala | 5 ++++- .../src/dotty/tools/dotc/core/Denotations.scala | 14 ++++++++++++-- .../src/dotty/tools/dotc/core/SymDenotations.scala | 3 +++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 545d10d5312e..ee16e4f39182 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -144,11 +144,6 @@ object Config { */ final val simplifyApplications = true - /** If this flag is on, automatically being forward no-longer valid package members. - * If it is off, raise a StaleSymbol error instead. - */ - final val autoUpdatePackageMembers = true - /** If set, prints a trace of all symbol completions */ final val showCompletions = false diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index e4f3137458ef..48ccc7528312 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -106,6 +106,7 @@ class ScalaSettings extends Settings.SettingGroup { val YkeepComments = BooleanSetting("-Ykeep-comments", "Keep comments when scanning source files.") val YforceSbtPhases = BooleanSetting("-Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.") val YdumpSbtInc = BooleanSetting("-Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.") + val YupdateStale = BooleanSetting("-Yupdate-stale", "Automically update stale top-level classes and objects to latest version") val YcheckAllPatmat = BooleanSetting("-Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm)") val YretainTrees = BooleanSetting("-Yretain-trees", "Retain trees for top-level classes, accessible from ClassSymbol#tree") val YshowTreeIds = BooleanSetting("-Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.") diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 6c4311b90322..33c80c4d3889 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -209,7 +209,7 @@ class Definitions { * members at runtime. */ lazy val ScalaShadowingPackageVal = ctx.requiredPackage(nme.scalaShadowing) - lazy val ScalaShadowingPackageClass = ScalaShadowingPackageVal.moduleClass.asClass + def ScalaShadowingPackageClass(implicit ctx: Context) = ScalaShadowingPackageVal.moduleClass.asClass /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) * because after erasure the Any and AnyVal references get remapped to the Object methods @@ -829,6 +829,9 @@ class Definitions { def isTupleClass(cls: Symbol) = isVarArityClass(cls, str.Tuple) def isProductClass(cls: Symbol) = isVarArityClass(cls, str.Product) + def isScalaShadowingPackageClass(cls: Symbol) = + cls.name == tpnme.scalaShadowing && cls.owner == RootClass + /** Returns the erased class of the function class `cls` * - FunctionN for N > 22 becomes FunctionXXL * - FunctionN for 22 > N >= 0 remains as FunctionN diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index cc8bb3a12759..96838986c572 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -774,16 +774,26 @@ object Denotations { /** Move validity period of this denotation to a new run. Throw a StaleSymbol error * if denotation is no longer valid. + * However, StaleSymbol error is not thrown in the following situations: + * + * - If the symbol is a toplevel class or object and -Yupdate-stale is set. + * update the denotation to the new symbol with the same name instead. + * - If ctx.acceptStale returns true (because we are in the IDE), + * update the symbol to the new version if it exists, or return + * the old version otherwise. + * - If the symbol did not have a denotation that was defined at the current phase + * return a NoDenotation instead. */ private def bringForward()(implicit ctx: Context): SingleDenotation = { this match { case symd: SymDenotation => if (ctx.stillValid(symd)) return updateValidity() - if (Config.autoUpdatePackageMembers && symd.owner.is(Package)) { + lazy val staleOK = ctx.acceptStale(symd) + if (ctx.settings.YupdateStale.value && symd.owner.is(Package) || staleOK) { val newd = symd.owner.info.decls.lookup(symd.name) if (newd.exists) return newd + else if (staleOK) return updateValidity() } - if (ctx.acceptStale(symd)) return updateValidity() case _ => } if (!symbol.exists) return updateValidity() diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index bcb9e6f40c08..7dbc9dfe0389 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1490,6 +1490,8 @@ object SymDenotations { if (nxt.validFor.code > this.validFor.code) { this.nextInRun.asSymDenotation.asClass.enter(sym) } + if (defn.isScalaShadowingPackageClass(sym.owner)) + defn.ScalaPackageClass.enter(sym) // ScalaShadowing members are mirrored in ScalaPackage } } @@ -1847,6 +1849,7 @@ object SymDenotations { if (entry != null) { if (entry.sym == sym) return false mscope.unlink(entry) + if (sym.owner == defn.ScalaShadowingPackageClass) if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId } true From c3be42ef9a26cea4a50ee3615121766c3cfe694c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 12:58:06 +0100 Subject: [PATCH 42/58] Change treatment of signatures in TermRefs - don't compute members when unpickling termrefs, it caused cyclic reference errors on tasty-bootstrap. - to make this robust, have currentSignature in TermRef return a NotAMethof if not symbol or denotation is known. --- .../src/dotty/tools/dotc/core/Types.scala | 6 +++++- .../tools/dotc/core/tasty/TreeUnpickler.scala | 20 +++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7fc3951f8fda..a3e33d060e88 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1535,6 +1535,10 @@ object Types { else symbol.asSeenFrom(prefix).signature } + /** The signature of the current denotation if it is known without forcing. + * Otherwise the signature of the current symbol if it is known without forcing. + * Otherwise NotAMethod. + */ private def currentSignature(implicit ctx: Context): Signature = if (mySig != null) mySig else { @@ -1543,7 +1547,7 @@ object Types { else { val sym = currentSymbol if (sym.exists) sym.asSeenFrom(prefix).signature - else null + else Signature.NotAMethod } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 27a8001f3f7e..a056196d966c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -296,22 +296,16 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi readPackageRef().termRef case TYPEREF => val name = readName().toTypeName - if (Config.newScheme) { - val prefix = readType() - TypeRef(prefix, name, prefix.member(name)) - } - else TypeRef(readType(), name) + TypeRef(readType(), name) case TERMREF => val sname = readName() val prefix = readType() - if (Config.newScheme) - sname match { - case SignedName(name, sig) => - TermRef(prefix, name, prefix.member(name).atSignature(sig)) - case name => - TermRef(prefix, name, prefix.member(name)) - } - else TermRef(prefix, sname) + sname match { + case SignedName(name, sig) => + TermRef(prefix, name, prefix.member(name).atSignature(sig)) + case name => + TermRef(prefix, name) + } case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) case RECtype => From 24ca6c02e85cf6a1854fc3ecba70e33ffa4ed728 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 17:03:19 +0100 Subject: [PATCH 43/58] Drop all code under !newScheme --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 8 +- .../src/dotty/tools/dotc/config/Config.scala | 2 - .../dotty/tools/dotc/core/Designators.scala | 75 -- .../src/dotty/tools/dotc/core/Names.scala | 12 +- .../tools/dotc/core/SymDenotations.scala | 14 +- .../src/dotty/tools/dotc/core/Symbols.scala | 23 +- .../src/dotty/tools/dotc/core/Types.scala | 718 ++++-------------- .../src/dotty/tools/dotc/core/Uniques.scala | 11 +- .../dotc/core/classfile/ClassfileParser.scala | 5 +- .../dotc/core/tasty/TastyUnpickler.scala | 2 +- .../tools/dotc/core/tasty/TreePickler.scala | 9 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 26 +- .../core/unpickleScala2/Scala2Unpickler.scala | 17 +- .../dotc/transform/ParamForwarding.scala | 20 +- .../tools/dotc/transform/PostTyper.scala | 8 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 5 +- 17 files changed, 201 insertions(+), 756 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/core/Designators.scala diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index d5f4d334a963..ad126fe4ba9f 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -709,8 +709,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val tp = if (sym.isType) { assert(!sym.is(TypeParam)) - if (config.Config.newScheme) TypeRef.withSym(tree.tpe, sym.asType) - else TypeRef(tree.tpe, sym.name.asTypeName) + TypeRef(tree.tpe, sym.asType) } else TermRef(tree.tpe, sym.name.asTermName, sym.denot.asSeenFrom(tree.tpe)) @@ -719,10 +718,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** A select node with the given selector name and signature and a computed type */ def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context): Tree = - untpd.SelectWithSig(tree, name, sig) - .withType( - if (config.Config.newScheme) tree.tpe.select(name.asTermName, sig) - else TermRef(tree.tpe, name.asTermName.withSig(sig))) + untpd.SelectWithSig(tree, name, sig).withType(tree.tpe.select(name.asTermName, sig)) /** A select node with selector name and signature taken from `sym`. * Note: Use this method instead of select(sym) if the referenced symbol diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index ee16e4f39182..4e4156079026 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -179,6 +179,4 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - - val newScheme = true } diff --git a/compiler/src/dotty/tools/dotc/core/Designators.scala b/compiler/src/dotty/tools/dotc/core/Designators.scala deleted file mode 100644 index 210b3fc36d06..000000000000 --- a/compiler/src/dotty/tools/dotc/core/Designators.scala +++ /dev/null @@ -1,75 +0,0 @@ -package dotty.tools -package dotc -package core - -import Names._ -import NameKinds.SignedName -import Types.{TypeRef, NameSpace, noNameSpace} -import Symbols.Symbol -import Contexts.Context - -/** Defines a common superclass of Name and Symbol and its Term/Type variants - * Designators are used in reference type to identity what is referred to. - */ -object Designators { - - abstract class Designator extends util.DotClass { self => - - type ThisName <: Name - - /** Classifiers and casts, to be overridden in implemetations */ - def isTerm(implicit ctx: Context) = false - def isType(implicit ctx: Context) = false - - def asTerm(implicit ctx: Context): TermDesignator - def asType(implicit ctx: Context): TypeDesignator - - def withNameSpace(space: NameSpace)(implicit ctx: Context): Designator { type ThisName = self.ThisName } = - if (space == noNameSpace) this - else localName(this.asInstanceOf[ThisName], space) - - /** Localize this name to the owner of `sym` if `sym` is private */ - def localizeIfPrivate(sym: Symbol)(implicit ctx: Context): Designator { type ThisName = self.ThisName } = - if (sym.isPrivate) withNameSpace(sym.owner.typeRef) else this - - def withSig(sig: Signature): Designator{ type ThisName = TermName } = { - val unsigned = this.asInstanceOf[TermName].exclude(SignedName) - if (sig eq Signature.NotAMethod) unsigned else SignedName(unsigned, sig) - } - } - - type TermDesignator = Designator { type ThisName = TermName } - type TypeDesignator = Designator { type ThisName = TypeName } - - /** Names that come with the namespace where they are defined. - * Used to give a stable reference to private names, and also to - * Scala 2x inner classes. - */ - case class LocalName[N <: Name](name: N, nameSpace: TypeRef) extends Designator { - type ThisName = N - - override def isTerm(implicit ctx: Context) = name.isTermName - override def isType(implicit ctx: Context) = name.isTypeName - - override def asTerm(implicit ctx: Context): TermDesignator = { - name.asTermName - this.asInstanceOf[TermDesignator] - } - override def asType(implicit ctx: Context): TypeDesignator = { - name.asTypeName - this.asInstanceOf[TypeDesignator] - } - - override def withNameSpace(space: NameSpace)(implicit ctx: Context) = - name.withNameSpace(space).asInstanceOf[Designator { type ThisName = N }] - - override def withSig(sig: Signature) = - LocalName(name.withSig(sig).asInstanceOf[TermName], nameSpace) - } - - /** Introduced to overcome shortcoming with refined type inference of case classes: - * LocalName's result type is always Designator, without a refinement. - */ - def localName[N <: Name](name: N, nameSpace: TypeRef): Designator { type ThisName = N } = - LocalName(name, nameSpace).asInstanceOf[Designator { type ThisName = N }] -} \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index af92bbb4ecdb..a45053202793 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -9,7 +9,6 @@ import Texts.Text import Decorators._ import Contexts.Context import StdNames.str -import Designators._ import util.Chars.isIdentifierStart import collection.IndexedSeqOptimized import collection.immutable @@ -30,6 +29,11 @@ object Names { implicit def eqName: Eq[Name, Name] = Eq + /** A common superclass of Name and Symbol. After bootstrap, this should be + * just the type alias Name | Symbol + */ + abstract class Designator extends util.DotClass + /** A name if either a term name or a type name. Term names can be simple * or derived. A simple term name is essentially an interned string stored * in a name table. A derived term name adds a tag, and possibly a number @@ -151,12 +155,6 @@ object Names { /** Does (the last part of) this name end with `str`? */ def endsWith(str: String): Boolean = lastPart.endsWith(str) - /** Designator overrides */ - override def isTerm(implicit ctx: Context) = isTermName - override def isType(implicit ctx: Context) = isTypeName - override def asTerm(implicit ctx: Context) = asTermName - override def asType(implicit ctx: Context) = asTypeName - override def hashCode = System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 7dbc9dfe0389..b36d37c51136 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1134,12 +1134,10 @@ object SymDenotations { def thisType(implicit ctx: Context): Type = NoPrefix override def typeRef(implicit ctx: Context): TypeRef = - if (Config.newScheme) TypeRef.withSym(owner.thisType, symbol.asType) - else TypeRef(owner.thisType, name.asTypeName, this) + TypeRef(owner.thisType, symbol) override def termRef(implicit ctx: Context): TermRef = - if (Config.newScheme) TermRef.withSym(owner.thisType, symbol.asTerm) - else TermRef(owner.thisType, name.asTermName, this) + TermRef(owner.thisType, symbol) /** The variance of this type parameter or type member as an Int, with * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter @@ -1440,10 +1438,9 @@ object SymDenotations { if (classParents.isEmpty && !emptyParentsExpected) onBehalf.signalProvisional() val builder = new BaseDataBuilder - for (p <- classParents) { - assert(p.typeSymbol.isClass, s"$this has $p") + for (p <- classParents) builder.addAll(p.typeSymbol.asClass.baseClasses) - } + (classSymbol :: builder.baseClasses, builder.baseClassSet) } @@ -1849,8 +1846,7 @@ object SymDenotations { if (entry != null) { if (entry.sym == sym) return false mscope.unlink(entry) - if (sym.owner == defn.ScalaShadowingPackageClass) - if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId + if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId // ### check if needed } true } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 4a1fc005f306..d9a73442ebdd 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -10,7 +10,6 @@ import java.lang.AssertionError import Decorators._ import Symbols._ import Contexts._ -import Designators._ import SymDenotations._ import printing.Texts._ import printing.Printer @@ -158,9 +157,7 @@ trait Symbols { this: Context => infoFn(module, modcls), privateWithin) val mdenot = SymDenotation( module, owner, name, modFlags | ModuleValCreationFlags, - if (cdenot.isCompleted) - if (config.Config.newScheme) TypeRef.withSym(owner.thisType, modcls) - else TypeRef.withSymOLD(owner.thisType, modcls, modclsName) + if (cdenot.isCompleted) TypeRef(owner.thisType, modcls) else new ModuleCompleter(modcls)) module.denot = mdenot modcls.denot = cdenot @@ -185,9 +182,7 @@ trait Symbols { this: Context => newModuleSymbol( owner, name, modFlags, clsFlags, (module, modcls) => ClassInfo( - owner.thisType, modcls, parents, decls, - if (config.Config.newScheme) TermRef.withSym(owner.thisType, module) - else TermRef.withSymOLD(owner.thisType, module, name)), + owner.thisType, modcls, parents, decls, TermRef(owner.thisType, module)), privateWithin, coord, assocFile) val companionMethodFlags = Flags.Synthetic | Flags.Private | Flags.Method @@ -295,10 +290,7 @@ trait Symbols { this: Context => for (name <- names) { val tparam = newNakedSymbol[TypeName](NoCoord) tparamBuf += tparam - trefBuf += ( - if (config.Config.newScheme) TypeRef.withSym(owner.thisType, tparam) - else TypeRef.withSymOLD(owner.thisType, tparam, name) - ) + trefBuf += TypeRef(owner.thisType, tparam) } val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) @@ -463,16 +455,15 @@ object Symbols { // denotations pointing to the new symbol, so the validity periods check out OK. // But once a package member is overridden it is not longerr valid. - /** Designator overrides */ - final override def isTerm(implicit ctx: Context): Boolean = + final def isTerm(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isTerm - final override def isType(implicit ctx: Context): Boolean = + final def isType(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isType - final override def asTerm(implicit ctx: Context): TermSymbol = { + final def asTerm(implicit ctx: Context): TermSymbol = { assert(isTerm, s"asTerm called on not-a-Term $this" ); asInstanceOf[TermSymbol] } - final override def asType(implicit ctx: Context): TypeSymbol = { + final def asType(implicit ctx: Context): TypeSymbol = { assert(isType, s"isType called on not-a-Type $this"); asInstanceOf[TypeSymbol] } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a3e33d060e88..0f3a5e1fde04 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -16,7 +16,6 @@ import SymDenotations._ import Decorators._ import Denotations._ import Periods._ -import Designators._ import util.Positions.{Position, NoPosition} import util.Stats._ import util.DotClass @@ -1134,8 +1133,7 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = - if (Config.newScheme) NamedType(this, name, member(name)).reduceProjection - else NamedType(this, name).reduceProjection + NamedType(this, name, member(name)).reduceProjection /** The type , reduced if possible, with given denotation if unreduced */ def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = // ### drop name @@ -1146,8 +1144,7 @@ object Types { NamedType.withSym(this, sym).reduceProjection def select(name: TermName)(implicit ctx: Context): TermRef = - if (Config.newScheme) TermRef(this, name, member(name)) - else TermRef(this, name) + TermRef(this, name, member(name)) def select(name: TermName, sig: Signature)(implicit ctx: Context): TermRef = TermRef(this, name, member(name).atSignature(sig, relaxed = !ctx.erasedTypes)) @@ -1505,25 +1502,46 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ - type NameSpace = TypeRef /* | Null */ - @sharable val noNameSpace: NameSpace = null + abstract class NamedType extends CachedProxyType with ValueType { self => + + type ThisType >: this.type <: NamedType + type ThisName <: Name - trait NamedTypeNEW extends NamedType { self => + val prefix: Type + def designator: Designator + protected def designator_=(d: Designator): Unit + + assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") private[this] var myName: Name = null private[this] var mySig: Signature = null + private[this] var lastDenotation: Denotation = null private[this] var lastSymbol: Symbol = null + private[this] var checkedPeriod: Period = Nowhere + + // Invariants: + // (1) checkedPeriod != Nowhere => lastDenotation != null + // (2) lastDenotation != null => lastSymbol != null - override def name(implicit ctx: Context): ThisName = { + def isType = isInstanceOf[TypeRef] + def isTerm = isInstanceOf[TermRef] + + /** If designator is a name, this name. Otherwise, the original name + * of the designator symbol. + */ + final def name(implicit ctx: Context): ThisName = { if (myName == null) myName = computeName myName.asInstanceOf[ThisName] } private def computeName: Name = designator match { case name: Name => name - case sym: Symbol => sym.lastKnownDenotation.initial.name + case sym: Symbol => sym.originDenotation.name } + /** The signature of the last known denotation, or if there is none, the + * signature of the symbol + */ final override def signature(implicit ctx: Context): Signature = { if (mySig == null) mySig = computeSignature mySig @@ -1551,7 +1569,7 @@ object Types { } } - override def symbol(implicit ctx: Context): Symbol = + final def symbol(implicit ctx: Context): Symbol = if (checkedPeriod == ctx.period) lastSymbol else computeSymbol private def computeSymbol(implicit ctx: Context): Symbol = @@ -1562,6 +1580,12 @@ object Types { (if (denotationIsCurrent) lastDenotation else denot).symbol } + /** There is a denotation computed which is valid (somewhere in) the + * current run. + */ + def denotationIsCurrent(implicit ctx: Context) = + lastDenotation != null && lastDenotation.validFor.runId == ctx.runId + /** If the reference is symbolic or the denotation is current, its symbol, otherwise NoDenotation. * * Note: This operation does not force the denotation, and is therefore @@ -1571,7 +1595,7 @@ object Types { * type accumulators, as well as to be safe in diagnostic printing. * Normally, it's better to use `symbol`, not `currentSymbol`. */ - override def currentSymbol(implicit ctx: Context) = designator match { + final def currentSymbol(implicit ctx: Context) = designator match { case sym: Symbol => sym case _ => if (denotationIsCurrent) lastDenotation.symbol else NoSymbol } @@ -1580,23 +1604,35 @@ object Types { * Assumes that symbols do not change between periods in the same run. * Used to get the class underlying a ThisType. */ - override protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { + final private[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { if (checkedPeriod.runId == ctx.runId) lastSymbol else symbol } - private def lastKnownSymbol = + private def lastKnownSymbol = // ### always combine with initial? if (lastDenotation != null) lastDenotation.symbol else NoSymbol - private def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = - symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) + def info(implicit ctx: Context): Type = denot.info - override def isMemberRef(implicit ctx: Context) = designator match { - case sym: Symbol => infoDependsOnPrefix(sym, prefix) - case _ => true + /** The denotation currently denoted by this type */ + final def denot(implicit ctx: Context): Denotation = { + val now = ctx.period + val lastd = lastDenotation + if (checkedPeriod == now) lastd else denotAt(lastd, now) + } + + /** A first fall back to do a somewhat more expensive calculation in case the first + * attempt in `denot` does not yield a denotation. + */ + private def denotAt(lastd: Denotation, now: Period)(implicit ctx: Context): Denotation = { + if (lastd != null && (lastd.validFor contains now)) { + checkedPeriod = now + lastd + } + else computeDenot } - override protected def computeDenot(implicit ctx: Context): Denotation = { + private def computeDenot(implicit ctx: Context): Denotation = { def finish(d: Denotation) = { if (ctx.typerState.ephemeral) @@ -1665,6 +1701,9 @@ object Types { d } + def reloadDenot()(implicit ctx: Context) = // ### combine with invalidate(?) + setDenot(loadDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))) + protected def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) @@ -1683,10 +1722,13 @@ object Types { else d } - override def checkDenot()(implicit ctx: Context) = {} + private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { // ### make private? (also others) + if (ctx.isAfterTyper) + assert(!denot.isOverloaded, this) + if (Config.checkNoDoubleBindings) + if (ctx.settings.YnoDoubleBindings.value) + checkSymAssign(denot.symbol) - protected[dotc] override def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { - if (ctx.isAfterTyper) assert(!denot.isOverloaded, this) lastDenotation = denot lastSymbol = denot.symbol checkedPeriod = ctx.period @@ -1698,306 +1740,17 @@ object Types { checkDenot() } - protected[dotc] override def withSym(sym: Symbol)(implicit ctx: Context): ThisType = - if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] - else this - - override protected[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = - if (denot.exists) { - val adapted = withSym(denot.symbol) - if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] - else { - setDenot(denot) - this - } - } - else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala. - this - - /** Create a NamedType of the same kind as this type, but with a new prefix. - */ - override def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { - def reload(): NamedType = { - val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol - var d = memberDenot(prefix, name, allowPrivate) - if (d.isOverloaded && lastSymbol.exists) { - val targetSig = - if (lastSymbol.signature == Signature.NotAMethod) Signature.NotAMethod - else lastSymbol.asSeenFrom(prefix).signature - d = d.atSignature(targetSig, relaxed = !ctx.erasedTypes) - } - NamedType(prefix, name, d) - } - if (lastDenotation == null) NamedType(prefix, designator) - else designator match { - case sym: Symbol => - if (infoDependsOnPrefix(sym, prefix)) { - val candidate = reload() - val falseOverride = sym.isClass && candidate.symbol.exists && candidate.symbol != symbol - // A false override happens if we rebind an inner class to another type with the same name - // in an outer subclass. This is wrong, since classes do not override. We need to - // return a type with the existing class info as seen from the new prefix instead. - if (falseOverride) NamedType(prefix, sym.name, denot.asSeenFrom(prefix)) - else candidate - } - else NamedType(prefix, sym) - case name: Name => reload() - } - } - } - - trait TermRefNEW extends TermRef with NamedTypeNEW { - - override def alternatives(implicit ctx: Context): List[TermRef] = - denot.alternatives.map(withDenot(_)) - - override def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = - denot.altsWith(p).map(withDenot(_)) - } - - trait TypeRefNEW extends TypeRef with NamedTypeNEW - - final class CachedTermRefNEW(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) with TermRefNEW { - assert((prefix ne NoPrefix) || hasFixedSym) - myHash = hc - } - - final class CachedTypeRefNEW(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) with TypeRefNEW { - assert((prefix ne NoPrefix) || hasFixedSym) - myHash = hc - } - - /** A NamedType of the form Prefix # name */ - abstract class NamedType extends CachedProxyType with ValueType { self => - - type ThisType >: this.type <: NamedType - type ThisName <: Name - - val prefix: Type - def designator: Designator { type ThisName = self.ThisName } - def designator_=(d: Designator { type ThisName = self.ThisName }): Unit - - assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") - - def isType = isInstanceOf[TypeRef] - def isTerm = isInstanceOf[TermRef] - def hasFixedSym = designator.isInstanceOf[Symbol] - - private[this] var myName: ThisName = _ - private[this] var mySig: Signature = null - private[this] var myNameSpace: NameSpace = noNameSpace - - private[dotc] def init()(implicit ctx: Context): this.type = { - assert(!Config.newScheme) - def decompose(designator: Designator): Unit = designator match { - case DerivedName(underlying, info: SignedName.SignedInfo) => - mySig = info.sig - decompose(underlying) - case designator: Name => - myName = designator.asInstanceOf[ThisName] - if (mySig == null) mySig = Signature.NotAMethod - case designator: Symbol => - uncheckedSetSym(designator) - case designator: LocalName[_] => - myNameSpace = designator.nameSpace - decompose(designator.name) - } - decompose(designator) - this - } - - def name(implicit ctx: Context): ThisName = { - assert(!Config.newScheme) - if (myName == null) - myName = designator.asInstanceOf[Symbol].name.asInstanceOf[ThisName] - myName - } - - override def signature(implicit ctx: Context): Signature = { - if (mySig == null) mySig = denot.signature - mySig - } - - final def nameSpace: NameSpace = myNameSpace - - protected[this] var lastDenotation: Denotation = _ - private[this] var lastSymbol: Symbol = _ - protected[this] var checkedPeriod = Nowhere - - // Invariants: - // (1) checkedPeriod != Nowhere => lastDenotation != null - // (2) lastDenotation != null => lastSymbol != null - - /** There is a denotation computed which is valid (somewhere in) the - * current run. - */ - def denotationIsCurrent(implicit ctx: Context) = - lastDenotation != null && lastDenotation.validFor.runId == ctx.runId - - /** The denotation is current, its symbol, otherwise NoDenotation. - * - * Note: This operation does not force the denotation, and is therefore - * timing dependent. It should only be used if the outcome of the - * essential computation does not depend on the symbol being present or not. - * It's currently used to take an optimized path in substituters and - * type accumulators, as well as to be safe in diagnostic printing. - * Normally, it's better to use `symbol`, not `currentSymbol`. - */ - def currentSymbol(implicit ctx: Context) = { - assert(!Config.newScheme) - if (denotationIsCurrent) symbol else NoSymbol - } - - /** The denotation currently denoted by this type */ - final def denot(implicit ctx: Context): Denotation = { - val now = ctx.period - val lastd = lastDenotation - if (checkedPeriod == now) lastd else denotAt(lastd, now) - } - - /** A first fall back to do a somewhat more expensive calculation in case the first - * attempt in `denot` does not yield a denotation. - */ - private def denotAt(lastd: Denotation, now: Period)(implicit ctx: Context): Denotation = { - if (lastd != null && (lastd.validFor contains now)) { - checkedPeriod = now - lastd - } - else computeDenot - } - - var prevDenotation: Denotation = _ - - /** Hook for adding debug check code when denotations are assigned */ - def checkDenot()(implicit ctx: Context) = { - if (Config.checkTypeRefCycles) - lastDenotation match { - case d: SingleDenotation => - d.infoOrCompleter match { - case TypeBounds(lo, hi) => - assert(lo ne this, this) - assert(hi ne this, this) - case _ => - } - case _ => - } - if (Config.checkTypeParamRefs) - lastDenotation match { - case d: SingleDenotation if d.symbol.is(ClassTypeParam) => - prefix match { - case prefix: Types.ThisType => assert(prefix.cls == d.symbol.owner, this) - case _ => assert(false, this) - } - case _ => - } - } - - /** A second fallback to recompute the denotation if necessary */ - protected def computeDenot(implicit ctx: Context): Denotation = { - assert(!Config.newScheme) - val savedEphemeral = ctx.typerState.ephemeral - ctx.typerState.ephemeral = false - try { - prevDenotation = lastDenotation - def finish(d: Denotation) = - if (ctx.typerState.ephemeral) { record("ephemeral cache miss: loadDenot"); d } - else if (d.exists) { - // Avoid storing NoDenotations in the cache - we will not be able to recover from - // them. The situation might arise that a type has NoDenotation in some later - // phase but a defined denotation earlier (e.g. a TypeRef to an abstract type - // is undefined after erasure.) We need to be able to do time travel back and - // forth also in these cases. - - // Don't use setDenot here; double binding checks can give spurious failures after erasure - lastDenotation = d - lastSymbol = d.symbol - checkedPeriod = ctx.period - checkDenot() - d - } - else d - val d = lastDenotation match { - case null => - val sym = lastSymbol - if (sym != null && sym.isValidInCurrentRun) - if (!Config.newScheme || - (prefix eq NoPrefix) || (prefix eq sym.maybeOwner.thisType) || sym.isReferencedSymbolically) - finish(denotOfSym(sym)) - else if (Config.newScheme && sym.isClass) finish(denotOfSym(sym)) - else finish(loadDenot) - else finish(loadDenot) - case d: SymDenotation => - if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) - if (hasFixedSym) - finish(d.current) - else if (nameSpace != noNameSpace || - d.exists && prefix.isTightPrefix(d.owner) || - d.isConstructor) finish(d.current) - else - finish(recomputeMember(d)) // symbol could have been overridden, recompute membership - else if (hasFixedSym && d.validFor == Nowhere) // denotation was invalidated - finish(d.current) - else finish(try { - val newd = loadDenot // TODO: If symbolic re-enter in uniques map. - if (newd.exists) newd - else if (ctx.mode.is(Mode.Interactive)) d - else d.staleSymbolError - } - catch { - case ex: Error => - println(d) - println(d.validFor.runId) - println(ctx.runId) - println(hasFixedSym) - println(i"prefix = $prefix / ${prefix.member(name)}") - throw ex - }) - case d => - if (d.validFor.runId != ctx.period.runId) finish(loadDenot) - else finish(d.current) - } - d - } - finally ctx.typerState.ephemeral |= savedEphemeral - } - - /** A member of `prefix` (disambiguated by `d.signature`) or, if none was found, `d.current`. */ - private def recomputeMember(d: SymDenotation)(implicit ctx: Context): Denotation = { - assert(!Config.newScheme) - asMemberOf(prefix, allowPrivate = d.is(Private)) match { - case NoDenotation => d.current - case newd: SingleDenotation => newd - case newd => - newd.atSignature(d.signature) match { - case newd1: SingleDenotation if newd1.exists => newd1 - case _ => d.current - } - } - } - - protected def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = { - assert(!Config.newScheme) - val d = sym.denot - val owner = d.owner - if (owner.isTerm) d else d.asSeenFrom(prefix) - } + private def checkDenot()(implicit ctx: Context) = {} private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = { - assert(!Config.newScheme) def selfTypeOf(sym: Symbol) = if (sym.isClass) sym.asClass.givenSelfType else NoType assert( (lastSymbol eq sym) || (lastSymbol eq null) - || { - val lastDefRunId = lastDenotation match { - case d: SymDenotation => d.validFor.runId - case _ => lastSymbol.defRunId - } - (lastDefRunId != sym.defRunId) || - (lastDefRunId == NoRunId) - } + || + !denotationIsCurrent || lastSymbol.infoOrCompleter.isInstanceOf[ErrorType] || @@ -2009,115 +1762,25 @@ object Types { selfTypeOf(sym).derivesFrom(lastSymbol.owner) || selfTypeOf(lastSymbol).derivesFrom(sym.owner) - ), - i"""data race? overwriting symbol of type $this, - |long form = $toString of class $getClass, + ) + || + sym == defn.AnyClass.primaryConstructor, + s"""data race? overwriting $lastSymbol with $sym in type $this, |last sym id = ${lastSymbol.id}, new sym id = ${sym.id}, |last owner = ${lastSymbol.owner}, new owner = ${sym.owner}, |period = ${ctx.phase} at run ${ctx.runId}""") } - protected[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { - assert(!Config.newScheme) - val adapted = - if (hasFixedSym) - if (Config.newScheme) withSym(denot.symbol) - else this - else if (signature != denot.signature) - withSig(denot.signature) - else if (denot.symbol.isPrivate) { - assert(!Config.newScheme) - withNameSpaceOLD(denot.symbol.owner.typeRef) - } - else - this - if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] - else { - setDenot(denot) - this - } - } - - protected[dotc] def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { - assert(!Config.newScheme) - if (Config.checkNoDoubleBindings) - if (ctx.settings.YnoDoubleBindings.value) - checkSymAssign(denot.symbol) - - // additional checks that intercept `denot` can be added here - - lastDenotation = denot - checkDenot() - lastSymbol = denot.symbol - checkedPeriod = Nowhere - } - - protected[dotc] def withSym(sym: Symbol)(implicit ctx: Context): ThisType = { - assert(!Config.newScheme) - setSym(sym) - this - } - - private[dotc] final def setSym(sym: Symbol)(implicit ctx: Context): Unit = { - assert(!Config.newScheme) - if (Config.checkNoDoubleBindings) - if (ctx.settings.YnoDoubleBindings.value) - checkSymAssign(sym) - uncheckedSetSym(sym) - } - - private[dotc] final def uncheckedSetSym(sym: Symbol): Unit = { - assert(!Config.newScheme) - lastDenotation = null - lastSymbol = sym - checkedPeriod = Nowhere - } - - private def withSig(sig: Signature)(implicit ctx: Context): NamedType = { - assert(!Config.newScheme) - TermRef(prefix, designator.withSig(sig)) - } - - private def loadDenot(implicit ctx: Context): Denotation = { - assert(!Config.newScheme) - val d = asMemberOf(prefix, allowPrivate = - Config.newScheme && lastSymbol != null && lastSymbol.is(Private)) - def atSig(sig: Signature): Denotation = - if (sig.ne(Signature.OverloadedSignature)) d.atSignature(sig).checkUnique - else d - if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (d.isOverloaded) - if (hasFixedSym) { - val last = - if (lastDenotation != null) lastDenotation - else symbol.lastKnownDenotation.asSeenFrom(prefix) - atSig(last.signature) - } - else if (mySig != null) atSig(mySig) - else d - else d - else { // name has changed; try load in earlier phase and make current - - val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current - if (d.exists) d - else throw new Error(s"failure to reload $this of class $getClass") - } - } - - def reloadDenot()(implicit ctx: Context) = { - assert(!Config.newScheme) - setDenot(loadDenot) - } + // ### make private or add comment + def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = + symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) - protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { - assert(!Config.newScheme) - if (nameSpace != noNameSpace) nameSpace.findMember(name, prefix, EmptyFlags) - else if (allowPrivate) prefix.member(name) - else prefix.nonPrivateMember(name) + /** Is this a reference to a class or object member? */ + def isMemberRef(implicit ctx: Context) = designator match { + case sym: Symbol => infoDependsOnPrefix(sym, prefix) + case _ => true } - def isMemberRef(implicit ctx: Context) = !hasFixedSym - /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. * @@ -2132,27 +1795,6 @@ object Types { } else this - def symbol(implicit ctx: Context): Symbol = { - assert(!Config.newScheme) - if (checkedPeriod == ctx.period || - lastDenotation == null && lastSymbol != null && lastSymbol.isValidInCurrentRun) - lastSymbol - else - denot.symbol - } - - /** Retrieves currently valid symbol without necessarily updating denotation. - * Assumes that symbols do not change between periods in the same run. - * Used to get the class underlying a ThisType. - */ - protected[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { - assert(!Config.newScheme) - if (checkedPeriod.runId == ctx.runId) lastSymbol - else symbol - } - - def info(implicit ctx: Context): Type = denot.info - /** Guard against cycles that can arise if given `op` * follows info. The problematic cases are a type alias to itself or * bounded by itself or a val typed as itself: @@ -2180,8 +1822,6 @@ object Types { ctx.underlyingRecursions -= 1 } - // def noArg = throw new AssertionError(s"$pre contains no matching argument for ${sym.showLocated}") - /** The argument corresponding to class type parameter `tparam` as seen from * prefix `pre`. */ @@ -2261,15 +1901,57 @@ object Types { case _ => withPrefix(prefix) } - /** Create a NamedType of the same kind as this type, but with a new prefix. - */ - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType + private[dotc] final def invalidateDenot()(implicit ctx: Context): Unit = { + lastDenotation = null + lastSymbol = null + } - /** Create a NamedType of the same kind as this type, but with a new namespace. + private[dotc] final def withSym(sym: Symbol)(implicit ctx: Context): ThisType = + if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] + else this + + private[dotc] final def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = + if (denot.exists) { + val adapted = withSym(denot.symbol) + if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] + else { + setDenot(denot) + this + } + } + else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala. + this + + /** Create a NamedType of the same kind as this type, but with a new prefix. */ - def withNameSpaceOLD(nameSpace: NameSpace)(implicit ctx: Context): NamedType = - if (nameSpace == this.nameSpace) this - else NamedType(prefix, designator.withNameSpace(nameSpace)) + final def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { + def reload(): NamedType = { + val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol + var d = memberDenot(prefix, name, allowPrivate) + if (d.isOverloaded && lastSymbol.exists) { + val targetSig = + if (lastSymbol.signature == Signature.NotAMethod) Signature.NotAMethod + else lastSymbol.asSeenFrom(prefix).signature + d = d.atSignature(targetSig, relaxed = !ctx.erasedTypes) + } + NamedType(prefix, name, d) + } + if (lastDenotation == null) NamedType(prefix, designator) + else designator match { + case sym: Symbol => + if (infoDependsOnPrefix(sym, prefix)) { + val candidate = reload() + val falseOverride = sym.isClass && candidate.symbol.exists && candidate.symbol != symbol + // A false override happens if we rebind an inner class to another type with the same name + // in an outer subclass. This is wrong, since classes do not override. We need to + // return a type with the existing class info as seen from the new prefix instead. + if (falseOverride) NamedType(prefix, sym.name, denot.asSeenFrom(prefix)) + else candidate + } + else NamedType(prefix, sym) + case name: Name => reload() + } + } override def equals(that: Any) = that match { case that: NamedType => @@ -2282,18 +1964,9 @@ object Types { override def computeHash = unsupported("computeHash") override def eql(that: Type) = this eq that // safe because named types are hash-consed separately - - /* A version of toString which also prints aliases. Can be used for debugging - override def toString = - if (isTerm) s"TermRef($prefix, $name)" - else s"TypeRef($prefix, $name)${ - if (lastDenotation != null && lastDenotation.infoOrCompleter.isAlias) - s"@@@ ${lastDenotation.infoOrCompleter.asInstanceOf[TypeAlias].hi}" - else ""}" - */ } - abstract case class TermRef(override val prefix: Type, var designator: TermDesignator) extends NamedType with SingletonType { + abstract case class TermRef(override val prefix: Type, var designator: Designator) extends NamedType with SingletonType { type ThisType = TermRef type ThisName = TermName @@ -2306,75 +1979,28 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded - private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = { - assert(!Config.newScheme) - TermRef.apply(prefix, name, sd) - } - - def alternatives(implicit ctx: Context): List[TermRef] = { - assert(!Config.newScheme) - denot.alternatives map rewrap - } - - def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = { - assert(!Config.newScheme) - denot.altsWith(p) map rewrap - } - - private def fixDenot(candidate: TermRef, prefix: Type)(implicit ctx: Context): TermRef = - if (symbol.exists && !candidate.symbol.exists) { // recompute from previous symbol - assert(!Config.newScheme) - val ownSym = symbol - val newd = asMemberOf(prefix, allowPrivate = ownSym.is(Private)) - candidate.withDenot(newd.suchThat(_.signature == ownSym.signature)) - } - else candidate + def alternatives(implicit ctx: Context): List[TermRef] = + denot.alternatives.map(withDenot(_)) - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = designator match { - case designator: TermSymbol @unchecked => - assert(!Config.newScheme) - TermRef(prefix, designator) - case _ => - assert(!Config.newScheme) - // If symbol exists, the new signature is the symbol's signature as seen - // from the new prefix, modulo consistency - val curSig = signature - val newSig = - if (curSig.eq(Signature.NotAMethod) || !symbol.exists) - curSig - else - curSig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) - val designator1 = - if (newSig ne curSig) { - core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") - designator.withSig(newSig) - } - else designator - assert(!Config.newScheme) - fixDenot(TermRef(prefix, designator1), prefix) - } + def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = + denot.altsWith(p).map(withDenot(_)) } - abstract case class TypeRef(override val prefix: Type, var designator: TypeDesignator) extends NamedType { + abstract case class TypeRef(override val prefix: Type, var designator: Designator) extends NamedType { type ThisType = TypeRef type ThisName = TypeName override def underlying(implicit ctx: Context): Type = info - - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { - assert(!Config.newScheme) - TypeRef(prefix, designator) - } } - final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { - assert((prefix ne NoPrefix) || hasFixedSym) + final class CachedTermRef(prefix: Type, designator: Designator, hc: Int) extends TermRef(prefix, designator) { + assert((prefix ne NoPrefix) || designator.isInstanceOf[Symbol]) myHash = hc } - final class CachedTypeRef(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) { - assert((prefix ne NoPrefix) || hasFixedSym) + final class CachedTypeRef(prefix: Type, designator: Designator, hc: Int) extends TypeRef(prefix, designator) { + assert((prefix ne NoPrefix) || designator.isInstanceOf[Symbol]) myHash = hc } @@ -2383,9 +2009,13 @@ object Types { if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) object NamedType { + def isType(desig: Designator)(implicit ctx: Context) = desig match { + case sym: Symbol => sym.isType + case name: Name => name.isTypeName + } def apply(prefix: Type, designator: Designator)(implicit ctx: Context) = - if (designator.isType) TypeRef.apply(prefix, designator.asType) - else TermRef.apply(prefix, designator.asTerm) + if (isType(designator)) TypeRef.apply(prefix, designator) + else TermRef.apply(prefix, designator) def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) else TypeRef.apply(prefix, designator.asTypeName, denot) @@ -2400,7 +2030,7 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def apply(prefix: Type, desig: TermDesignator)(implicit ctx: Context): TermRef = + def apply(prefix: Type, desig: Designator)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = true).asInstanceOf[TermRef] /** Create term ref to given initial denotation, taking the signature @@ -2408,60 +2038,24 @@ object Types { * signature, if denotation is not yet completed. */ def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = - if (Config.newScheme) - apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot) - else { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) - else denot match { - case denot: SingleDenotation => - apply(prefix, name.withSig(denot.signature).localizeIfPrivate(denot.symbol)) - case _ => apply(prefix, name) - } - } withDenot denot - - /** Create a term ref referring to given symbol with given name. - * This is similar to TermRef(Type, Symbol), except: - * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. - * (2) the designator of the TermRef is either the symbol or its name & unforced signature. - */ - def withSymOLD(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = { - assert(!Config.newScheme) - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name.withSig(sym.signature).localizeIfPrivate(sym)).withSym(sym) - } + apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot) def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) + apply(prefix, sym) // ### } object TypeRef { /** Create type ref with given prefix and name */ - def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = + def apply(prefix: Type, desig: Designator)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref with given name and initial denotation */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = - if (Config.newScheme) - apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot) - else { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) - else apply(prefix, name.localizeIfPrivate(denot.symbol)) - } withDenot denot - - /** Create a type ref referring to either a given symbol or its name. - * This is similar to TypeRef(prefix, sym), except: - * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. - * (2) the designator of the TypeRef is either the symbol or its name - */ - def withSymOLD(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = { - assert(!Config.newScheme) - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else apply(prefix, name.localizeIfPrivate(sym)).withSym(sym) - } + apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot) def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - if (Config.newScheme) apply(prefix, sym) else withSymOLD(prefix, sym, sym.name) + apply(prefix, sym) // ### } // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- @@ -3806,7 +3400,8 @@ object Types { def clsDenot = if (prefix eq cls.owner.thisType) cls.denot else cls.denot.copySymDenotation(info = this) if (appliedRefCache == null) { val tref = - if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef // ??? not always symbolicRef + if ((cls is PackageClass) || cls.owner.isTerm) + TypeRef(prefix, cls) // ### not always symbolicRef? else TypeRef(prefix, cls.name, clsDenot) appliedRefCache = tref.appliedTo(cls.typeParams.map(_.typeRef)) @@ -3814,8 +3409,6 @@ object Types { appliedRefCache } - def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef.withSym(prefix, cls) - // cached because baseType needs parents private[this] var parentsCache: List[Type] = null @@ -3887,9 +3480,10 @@ object Types { def contains(tp: Type)(implicit ctx: Context): Boolean = tp match { case tp: TypeBounds => lo <:< tp.lo && tp.hi <:< hi case tp: ClassInfo => + val cls = tp.cls // Note: Taking a normal typeRef does not work here. A normal ref might contain // also other information about the named type (e.g. bounds). - if (Config.newScheme) { + if (true) { // ### val loOK = lo.isRef(tp.cls) || lo.isRef(defn.NothingClass) || @@ -3902,7 +3496,9 @@ object Types { false } } - else contains(tp.symbolicTypeRef) + else contains( + TypeRef(tp.prefix, cls) + .withDenot(new UniqueRefDenotation(cls, tp, cls.validFor))) case _ => lo <:< tp && tp <:< hi } diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index bd5976fef84f..36228f418b9e 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc package core -import Types._, Symbols._, Contexts._, util.Stats._, Hashable._, Names._, Designators._ +import Types._, Symbols._, Contexts._, util.Stats._, Hashable._, Names._ import config.Config import Decorators._ import util.HashSet @@ -57,13 +57,8 @@ object Uniques { val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) def newType = - if (Config.newScheme) - if (isTerm) new CachedTermRefNEW(prefix, designator.asInstanceOf[TermDesignator], h) - else new CachedTypeRefNEW(prefix, designator.asInstanceOf[TypeDesignator], h) - else { - if (isTerm) new CachedTermRef(prefix, designator.asInstanceOf[TermDesignator], h) - else new CachedTypeRef(prefix, designator.asInstanceOf[TypeDesignator], h) - }.init() + if (isTerm) new CachedTermRef(prefix, designator, h) + else new CachedTypeRef(prefix, designator, h) if (h == NotCached) newType else { val r = findPrevious(h, prefix, designator) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 43ceaaaad83c..a210cb9a4671 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -319,10 +319,7 @@ class ClassfileParser( case 'L' => def processInner(tp: Type): Type = tp match { case tp: TypeRef if !(tp.symbol.owner is Flags.ModuleClass) => - if (config.Config.newScheme) - TypeRef.withSym(processInner(tp.prefix.widen), tp.symbol.asType) - else - TypeRef.withSymOLD(processInner(tp.prefix.widen), tp.symbol.asType, tp.name) + TypeRef(processInner(tp.prefix.widen), tp.symbol.asType) case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala index 394399d6bf60..9bbb7c83a510 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyUnpickler.scala @@ -64,7 +64,7 @@ class TastyUnpickler(reader: TastyReader) { val result = readName().toTypeName val params = until(end)(readName().toTypeName) var sig = Signature(params, result) - original.withSig(sig).asInstanceOf[TermName] + SignedName(original, sig) case _ => simpleNameKindOfTag(tag)(readName()) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 0b81850154ed..25125cfe334b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -9,7 +9,7 @@ import TastyFormat._ import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._ import collection.mutable import typer.Inliner -import NameOps._, NameKinds._, Designators._ +import NameOps._, NameKinds._ import StdNames.nme import TastyBuffer._ import TypeApplications._ @@ -193,13 +193,6 @@ class TreePickler(pickler: TastyPickler) { case name: Name => writeByte(if (tpe.isType) TYPEREF else TERMREF) pickleName(name); pickleType(tpe.prefix) - case LocalName(name, space) => - writeByte(if (tpe.isType) TYPEREFin else TERMREFin) - withLength { - pickleName(name) - pickleType(tpe.prefix) - pickleType(space) - } case sym: Symbol => pickleExternalRef(sym) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index a056196d966c..987a613eec9f 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -224,21 +224,18 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case TERMREFin => var sname = readName() val prefix = readType() - val space = readType().asInstanceOf[TypeRef] - if (Config.newScheme) - sname match { - case SignedName(name, sig) => - TermRef(prefix, name, space.decl(name).atSignature(sig)) - case name => - TermRef(prefix, name, space.decl(name)) - } - else TermRef(prefix, sname.withNameSpace(space)) + val space = readType() + sname match { + case SignedName(name, sig) => + TermRef(prefix, name, space.decl(name).atSignature(sig)) + case name => + TermRef(prefix, name, space.decl(name)) + } case TYPEREFin => val name = readName().toTypeName val prefix = readType() - val space = readType().asInstanceOf[TypeRef] - if (Config.newScheme) TypeRef(prefix, name, space.decl(name)) - else TypeRef(prefix, name.withNameSpace(space)) + val space = readType() + TypeRef(prefix, name, space.decl(name)) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -737,10 +734,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val start = currentAddr val cls = ctx.owner.asClass val assumedSelfType = - if (cls.is(Module) && cls.owner.isClass) - TermRef(cls.owner.thisType, - if (Config.newScheme) cls.name.sourceModuleName - else cls.name.sourceModuleName.localizeIfPrivate(cls)) + if (cls.is(Module) && cls.owner.isClass) TermRef(cls.owner.thisType, cls.name.sourceModuleName) else NoType cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 7e9290d3628d..7dd1d8c956dd 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -702,8 +702,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case SINGLEtpe => val pre = readTypeRef() val sym = readDisambiguatedSymbolRef(_.info.isParameterless) - if (config.Config.newScheme || isLocal(sym) || (pre eq NoPrefix)) pre select sym - else TermRef(pre, sym.name.asTermName) + pre.select(sym) case SUPERtpe => val thistpe = readTypeRef() val supertpe = readTypeRef() @@ -728,19 +727,11 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas pre = SuperType(thispre, base) } } + case NoPrefix if sym is TypeParam => + pre = sym.owner.thisType // ### needed? case _ => } - val tycon = - if (!config.Config.newScheme && sym.isClass && sym.is(Scala2x) && sym.owner.isClass && !sym.owner.is(Package)) - // There can be multiple Scala2 inner classes with the same prefix and name; use a namespace - // to pick a particular one. - TypeRef(pre, sym.name.asTypeName.withNameSpace(sym.owner.typeRef)) - else if (config.Config.newScheme || isLocal(sym) || pre == NoPrefix) { - val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre - pre1 select sym - } - else - TypeRef(pre, sym.name.asTypeName) + val tycon = pre.select(sym) val args = until(end, () => readTypeRef()) if (sym == defn.ByNameParamClass2x) ExprType(args.head) else if (args.nonEmpty) tycon.safeAppliedTo(EtaExpandIfHK(sym.typeParams, args.map(translateTempPoly))) diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 443e74e52cc2..8548ab6d7fc0 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -67,13 +67,8 @@ class ParamForwarding(thisPhase: DenotTransformer) { def forwarder(implicit ctx: Context) = { sym.copySymDenotation(initFlags = sym.flags | Method | Stable, info = sym.info.ensureMethodic) .installAfter(thisPhase) - var superAcc = + val superAcc = Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias) - if (alias.owner != currentClass.superClass && !config.Config.newScheme) - // need to use shadowed in order not to accidentally address an - // intervening private forwarder in the superclass - superAcc = superAcc.withType( - superAcc.tpe.asInstanceOf[TermRef].withNameSpaceOLD(noNameSpace)) typr.println(i"adding param forwarder $superAcc") DefDef(sym, superAcc.ensureConforms(sym.info.widen)) } @@ -91,16 +86,5 @@ class ParamForwarding(thisPhase: DenotTransformer) { cpy.Template(impl)(body = fwd(impl.body)(ctx.withPhase(thisPhase))) } - def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree.tpe match { - case tpe: TermRef - if !config.Config.newScheme && tpe.prefix.ne(NoPrefix) && tpe.signature.eq(Signature.NotAMethod) && tpe.symbol.is(Method) => - // It could be a param forwarder; adapt the signature - val newSig = tpe.prefix.memberInfo(tpe.symbol).signature - if (newSig.eq(Signature.NotAMethod)) tree - else tree.withType( - TermRef(tpe.prefix, tpe.name.withSig(newSig).localizeIfPrivate(tpe.symbol))) - .asInstanceOf[T] - case _ => - tree - } + def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree // ### } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index e098bb50a33e..cee6072a9086 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -83,13 +83,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase * signature, narrow the type by re-computing the signature (which should * be fully-defined by now). */ - private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree.tpe match { - case tpe: TermRef if tpe.signature.isUnderDefined => - assert(!config.Config.newScheme) - typr.println(i"fixing $tree with type ${tree.tpe.widen.toString} with sig ${tpe.signature} to ${tpe.widen.signature}") - tree.withType(TermRef(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] - case _ => tree - } + private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree // ### class PostTyperTransformer extends Transformer { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 23f1871c83e1..538905fff2e8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1200,7 +1200,7 @@ class Namer { typer: Typer => // fail with a bounds error in PostTyper. def ensureUpToDate(tp: Type, outdated: Type) = tp match { case tref: TypeRef if tref.info == outdated && sym.info != outdated => - tref.uncheckedSetSym(null) + tref.invalidateDenot() // ### verify still needed case _ => } ensureUpToDate(sym.typeRef, dummyInfo) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ae0a297b2606..fe0fec988c75 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -188,10 +188,7 @@ trait TypeAssigner { // an inherited non-private member with the same name and signature. val d2 = pre.nonPrivateMember(name) if (reallyExists(d2) && firstTry) - test( - if (config.Config.newScheme) NamedType(pre, name, d2) - else tpe.withNameSpaceOLD(noNameSpace).withDenot(d2), - false) + test(NamedType(pre, name, d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { TryDynamicCallType } else { From a1ae7f92256de075cd7e6bae9b85ba7643105d07 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 17:26:03 +0100 Subject: [PATCH 44/58] Drop NamedType.withSym --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +-- .../tools/dotc/core/SymDenotations.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 29 ++++++------------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- 6 files changed, 15 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ad126fe4ba9f..826256b30c6f 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -382,7 +382,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val targs = tp.argTypes val tycon = tp.typeConstructor New(tycon) - .select(TermRef.withSym(tycon, constr)) + .select(TermRef(tycon, constr)) .appliedToTypes(targs) .appliedToArgs(args) } @@ -926,7 +926,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } else denot.asSingleDenotation.termRef val fun = receiver - .select(TermRef.withSym(receiver.tpe, selected.termSymbol.asTerm)) + .select(TermRef(receiver.tpe, selected.termSymbol.asTerm)) .appliedToTypes(targs) def adaptLastArg(lastParam: Tree, expectedType: Type) = { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b36d37c51136..0fe19501c3fe 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1405,7 +1405,7 @@ object SymDenotations { private def computeThisType(implicit ctx: Context): Type = { val cls = symbol.asType val pre = if (this is Package) NoPrefix else owner.thisType - ThisType.raw(TypeRef.withSym(pre, cls)) + ThisType.raw(TypeRef(pre, cls)) } private[this] var myTypeRef: TypeRef = null diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0f3a5e1fde04..a98b88bb5aab 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -709,7 +709,7 @@ object Types { final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") { memberDenots(implicitFilter, (name, buf) => buf ++= member(name).altsWith(_ is Implicit)) - .toList.map(d => TermRef.withSym(this, d.symbol.asTerm)) + .toList.map(d => TermRef(this, d.symbol.asTerm)) } /** The set of member classes of this type */ @@ -1141,7 +1141,7 @@ object Types { /** The type with either `sym` or its signed name as designator, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = - NamedType.withSym(this, sym).reduceProjection + NamedType(this, sym).reduceProjection def select(name: TermName)(implicit ctx: Context): TermRef = TermRef(this, name, member(name)) @@ -2019,43 +2019,32 @@ object Types { def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) else TypeRef.apply(prefix, designator.asTypeName, denot) - def withSym(prefix: Type, sym: Symbol)(implicit ctx: Context): NamedType = - if (sym.isType) TypeRef.withSym(prefix, sym.asType) - else TermRef.withSym(prefix, sym.asTerm) } object TermRef { - /** Create term ref with given name, without specifying a signature. - * Its meaning is the (potentially multi-) denotation of the member(s) - * of prefix with given name. - */ + /** Create a term ref with given designator */ def apply(prefix: Type, desig: Designator)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = true).asInstanceOf[TermRef] - /** Create term ref to given initial denotation, taking the signature - * from the denotation if it is completed, or creating a term ref without - * signature, if denotation is not yet completed. + /** Create a term ref with given initial denotation. The name of the reference is taken + * from the denotation's symbol if the latter exists, or else it is the given name. */ def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = apply(prefix, if (denot.symbol.exists) denot.symbol.asTerm else name).withDenot(denot) - - def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - apply(prefix, sym) // ### } object TypeRef { - /** Create type ref with given prefix and name */ + /** Create a type ref with given prefix and name */ def apply(prefix: Type, desig: Designator)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] - /** Create a type ref with given name and initial denotation */ + /** Create a type ref with given initial denotation. The name of the reference is taken + * from the denotation's symbol if the latter exists, or else it is the given name. + */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = apply(prefix, if (denot.symbol.exists) denot.symbol.asType else name).withDenot(denot) - - def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - apply(prefix, sym) // ### } // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 987a613eec9f..19dc90b31d43 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -352,7 +352,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi private def readSymNameRef()(implicit ctx: Context): Type = { val sym = readSymRef() val prefix = readType() - val res = NamedType.withSym(prefix, sym) + val res = NamedType(prefix, sym) prefix match { case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot) // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index a7b3c601e013..6380fa14e18e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -386,7 +386,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => val companion = cls.companionModule if (companion.isTerm) { val prefix = receiver.tpe.baseType(cls).normalizedPrefix - if (prefix.exists) selectGetter(ref(TermRef.withSym(prefix, companion.asTerm))) + if (prefix.exists) selectGetter(ref(TermRef(prefix, companion.asTerm))) else EmptyTree } else EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 961538e09cd7..94306c08ee31 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1134,7 +1134,7 @@ class TermRefSet(implicit ctx: Context) extends mutable.Traversable[TermRef] { override def foreach[U](f: TermRef => U): Unit = for (sym <- elems.keysIterator) for (pre <- elems(sym)) - f(TermRef.withSym(pre, sym)) + f(TermRef(pre, sym)) } @sharable object EmptyTermRefSet extends TermRefSet()(NoContext) From 939d1e224b15ec71a52906f49c73cf4558c7a778 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 17:44:06 +0100 Subject: [PATCH 45/58] Replace invalidateDenot by reloadDenot --- .../dotty/tools/dotc/core/SymDenotations.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 16 ++++------------ compiler/src/dotty/tools/dotc/typer/Namer.scala | 4 ++-- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0fe19501c3fe..6ec252de93aa 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1846,7 +1846,7 @@ object SymDenotations { if (entry != null) { if (entry.sym == sym) return false mscope.unlink(entry) - if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId // ### check if needed + if (sym.name == nme.PACKAGE) packageObjRunId = NoRunId } true } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a98b88bb5aab..0a59dc3c51d3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1135,11 +1135,11 @@ object Types { def select(name: Name)(implicit ctx: Context): Type = NamedType(this, name, member(name)).reduceProjection - /** The type , reduced if possible, with given denotation if unreduced */ - def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = // ### drop name + /** The type with given denotation, reduced if possible. */ + def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = NamedType(this, name, denot).reduceProjection - /** The type with either `sym` or its signed name as designator, reduced if possible */ + /** The type , reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = NamedType(this, sym).reduceProjection @@ -1609,9 +1609,6 @@ object Types { else symbol } - private def lastKnownSymbol = // ### always combine with initial? - if (lastDenotation != null) lastDenotation.symbol else NoSymbol - def info(implicit ctx: Context): Type = denot.info /** The denotation currently denoted by this type */ @@ -1722,7 +1719,7 @@ object Types { else d } - private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { // ### make private? (also others) + private def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { // ### make private? (also others) if (ctx.isAfterTyper) assert(!denot.isOverloaded, this) if (Config.checkNoDoubleBindings) @@ -1901,11 +1898,6 @@ object Types { case _ => withPrefix(prefix) } - private[dotc] final def invalidateDenot()(implicit ctx: Context): Unit = { - lastDenotation = null - lastSymbol = null - } - private[dotc] final def withSym(sym: Symbol)(implicit ctx: Context): ThisType = if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] else this diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 538905fff2e8..f9f4493a6c1c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1195,12 +1195,12 @@ class Namer { typer: Typer => } // Here we pay the price for the cavalier setting info to TypeBounds.empty above. - // We need to compensate by invalidating caches in references that might + // We need to compensate by reloading the denotation of references that might // still contain the TypeBounds.empty. If we do not do this, stdlib factories // fail with a bounds error in PostTyper. def ensureUpToDate(tp: Type, outdated: Type) = tp match { case tref: TypeRef if tref.info == outdated && sym.info != outdated => - tref.invalidateDenot() // ### verify still needed + tref.reloadDenot() case _ => } ensureUpToDate(sym.typeRef, dummyInfo) From 5b4956128409dee1dad8998d3ae772f924d78235 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 17:51:20 +0100 Subject: [PATCH 46/58] Change visibility of some NamedType operations - make private where possible - make public where the operation is immutable and has a simple to understand meaning. --- .../src/dotty/tools/dotc/core/Types.scala | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0a59dc3c51d3..4de01b08af0f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1604,7 +1604,7 @@ object Types { * Assumes that symbols do not change between periods in the same run. * Used to get the class underlying a ThisType. */ - final private[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { + private[Types] def stableInRunSymbol(implicit ctx: Context): Symbol = { if (checkedPeriod.runId == ctx.runId) lastSymbol else symbol } @@ -1698,10 +1698,10 @@ object Types { d } - def reloadDenot()(implicit ctx: Context) = // ### combine with invalidate(?) + def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))) - protected def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = + private def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) private def disambiguate(d: Denotation)(implicit ctx: Context): Denotation = { @@ -1719,7 +1719,7 @@ object Types { else d } - private def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { // ### make private? (also others) + private def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { if (ctx.isAfterTyper) assert(!denot.isOverloaded, this) if (Config.checkNoDoubleBindings) @@ -1768,8 +1768,10 @@ object Types { |period = ${ctx.phase} at run ${ctx.runId}""") } - // ### make private or add comment - def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = + /** A reference with the initial symbol in `symd` has an info that + * might depend on the given prefix. + */ + private def infoDependsOnPrefix(symd: SymDenotation, prefix: Type)(implicit ctx: Context): Boolean = symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) /** Is this a reference to a class or object member? */ @@ -1898,11 +1900,11 @@ object Types { case _ => withPrefix(prefix) } - private[dotc] final def withSym(sym: Symbol)(implicit ctx: Context): ThisType = + final def withSym(sym: Symbol)(implicit ctx: Context): ThisType = if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] else this - private[dotc] final def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = + final def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = if (denot.exists) { val adapted = withSym(denot.symbol) if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] @@ -3379,14 +3381,9 @@ object Types { def appliedRef(implicit ctx: Context): Type = { def clsDenot = if (prefix eq cls.owner.thisType) cls.denot else cls.denot.copySymDenotation(info = this) - if (appliedRefCache == null) { - val tref = - if ((cls is PackageClass) || cls.owner.isTerm) - TypeRef(prefix, cls) // ### not always symbolicRef? - else TypeRef(prefix, cls.name, clsDenot) + if (appliedRefCache == null) appliedRefCache = - tref.appliedTo(cls.typeParams.map(_.typeRef)) - } + TypeRef(prefix, cls.name, clsDenot).appliedTo(cls.typeParams.map(_.typeRef)) appliedRefCache } From 0c87b7b217adf325901d863b28224b17cbbe021d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 26 Nov 2017 18:43:17 +0100 Subject: [PATCH 47/58] Resolve previously marked issues --- .../tools/dotc/core/SymDenotations.scala | 3 +-- .../src/dotty/tools/dotc/core/TypeOps.scala | 4 ---- .../src/dotty/tools/dotc/core/Types.scala | 21 ++++--------------- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotc/transform/ParamForwarding.scala | 2 -- .../tools/dotc/transform/PostTyper.scala | 10 ++------- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- 7 files changed, 9 insertions(+), 35 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 6ec252de93aa..44af9b6afeff 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -772,7 +772,6 @@ object SymDenotations { isPackageObject || isTerm && !is(MethodOrLazy, butNot = Label) && !isLocalDummy - // def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined def isSkolem: Boolean = name == nme.SKOLEM def isInlineMethod(implicit ctx: Context): Boolean = is(InlineMethod, butNot = Accessor) @@ -1678,7 +1677,7 @@ object SymDenotations { /*>|>*/ trace.onDebug(s"$tp.baseType($this)") /*<|<*/ { Stats.record("baseTypeOf") - tp.stripTypeVar match { // @!!! dealias? + tp.stripTypeVar match { case tp: CachedType => val btrCache = baseTypeCache try { diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 54ab8dff1d34..fee76e379914 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -63,8 +63,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. toPrefix(pre, cls, tp.cls) case _: BoundType | NoPrefix => tp - case tp: RefinedType => //@!!! todo: remove - derivedRefinedType(tp, apply(tp.parent), apply(tp.refinedInfo)) case _ => mapOver(tp) } @@ -101,8 +99,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } case _: ThisType | _: BoundType | NoPrefix => tp - case tp: RefinedType => // @!!! - tp.derivedRefinedType(simplify(tp.parent, theMap), tp.refinedName, simplify(tp.refinedInfo, theMap)) case tp: TypeAlias => tp.derivedTypeAlias(simplify(tp.alias, theMap)) case AndType(l, r) if !ctx.mode.is(Mode.Type) => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 4de01b08af0f..0fe46fa7363e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3461,23 +3461,10 @@ object Types { val cls = tp.cls // Note: Taking a normal typeRef does not work here. A normal ref might contain // also other information about the named type (e.g. bounds). - if (true) { // ### - val loOK = - lo.isRef(tp.cls) || - lo.isRef(defn.NothingClass) || - lo.isRef(defn.NullClass) && !tp.cls.isValueClass - val hiOK = - hi.isRef(tp.cls) || - tp.parents.exists(p => p <:< hi) - loOK && hiOK || { - println(i"NOT CONTAINS: $this / $tp") - false - } - } - else contains( - TypeRef(tp.prefix, cls) - .withDenot(new UniqueRefDenotation(cls, tp, cls.validFor))) - case _ => lo <:< tp && tp <:< hi + contains( + TypeRef(tp.prefix, cls).withDenot(new UniqueRefDenotation(cls, tp, cls.validFor))) + case _ => + lo <:< tp && tp <:< hi } def & (that: TypeBounds)(implicit ctx: Context): TypeBounds = diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 7dd1d8c956dd..a2542cbaefee 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -728,7 +728,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } } case NoPrefix if sym is TypeParam => - pre = sym.owner.thisType // ### needed? + pre = sym.owner.thisType case _ => } val tycon = pre.select(sym) diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 8548ab6d7fc0..52ef9b1d9a0a 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -85,6 +85,4 @@ class ParamForwarding(thisPhase: DenotTransformer) { cpy.Template(impl)(body = fwd(impl.body)(ctx.withPhase(thisPhase))) } - - def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree // ### } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index cee6072a9086..0bec80c49cb9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -79,12 +79,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase // TODO fill in } - /** If the type of `tree` is a TermRef with an underdefined - * signature, narrow the type by re-computing the signature (which should - * be fully-defined by now). - */ - private def fixSignature[T <: Tree](tree: T)(implicit ctx: Context): T = tree // ### - class PostTyperTransformer extends Transformer { private[this] var inJavaAnnot: Boolean = false @@ -170,7 +164,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case tree: Ident if !tree.isType => tree.tpe match { case tpe: ThisType => This(tpe.cls).withPos(tree.pos) - case _ => paramFwd.adaptRef(fixSignature(tree)) + case _ => tree } case tree @ Select(qual, name) => if (name.isTypeName) { @@ -178,7 +172,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase super.transform(tree) } else - transformSelect(paramFwd.adaptRef(fixSignature(tree)), Nil) + transformSelect(tree, Nil) case tree: Super => if (ctx.owner.enclosingMethod.isInlineMethod) ctx.error(SuperCallsNotAllowedInline(ctx.owner), tree.pos) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index f9f4493a6c1c..4c4a6dbd9acd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -754,7 +754,7 @@ class Namer { typer: Typer => else levels(c.outer) + 1 println(s"!!!completing ${denot.symbol.showLocated} in buried typerState, gap = ${levels(ctx)}") } - assert(ctx.runId == creationContext.runId, "completing $denot in wrong run ${ctx.runId}, was created in ${creationContext.runId}") + assert(ctx.runId == creationContext.runId, s"completing $denot in wrong run ${ctx.runId}, was created in ${creationContext.runId}") completeInCreationContext(denot) } From c3f43f9e9dbf6176dc4b05d9e642ceb939c6bb0b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 10:32:52 +0100 Subject: [PATCH 48/58] Polishings --- .../src/dotty/tools/dotc/config/Config.scala | 2 +- .../src/dotty/tools/dotc/core/Phases.scala | 3 --- .../tools/dotc/core/SymDenotations.scala | 17 +++++++------- .../src/dotty/tools/dotc/core/Symbols.scala | 15 ++++-------- .../src/dotty/tools/dotc/core/Types.scala | 19 ++++++++------- .../dotc/transform/ElimErasedValueType.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- tests/pending/pos/t2405.scala | 23 ------------------- 8 files changed, 26 insertions(+), 57 deletions(-) delete mode 100644 tests/pending/pos/t2405.scala diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 4e4156079026..60108d51d236 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -148,7 +148,7 @@ object Config { final val showCompletions = false /** If set, enables tracing */ - final val tracingEnabled = true + final val tracingEnabled = false /** Initial capacity of uniques HashMap. * Note: This MUST BE a power of two to work with util.HashSet diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 77f700454cad..61732763addc 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -321,7 +321,6 @@ object Phases { private[this] var myErasedTypes = false private[this] var myFlatClasses = false private[this] var myRefChecked = false - private[this] var mySymbolicRefs = false private[this] var myLabelsReordered = false private[this] var mySameMembersStartId = NoPhaseId @@ -340,7 +339,6 @@ object Phases { final def erasedTypes = myErasedTypes // Phase is after erasure final def flatClasses = myFlatClasses // Phase is after flatten final def refChecked = myRefChecked // Phase is after RefChecks - final def symbolicRefs = mySymbolicRefs // Phase is after ResolveSuper, newly generated TermRefs should be symbolic final def labelsReordered = myLabelsReordered // Phase is after LabelDefs, labels are flattened and owner chains don't mirror this final def sameMembersStartId = mySameMembersStartId @@ -357,7 +355,6 @@ object Phases { myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked - mySymbolicRefs = getClass == classOf[Erasure] || prev.symbolicRefs myLabelsReordered = prev.getClass == classOf[LabelDefs] || prev.labelsReordered mySameMembersStartId = if (changesMembers) id else prev.sameMembersStartId mySameParentsStartId = if (changesParents) id else prev.sameMembersStartId diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 44af9b6afeff..27f9e02b5a15 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1437,9 +1437,10 @@ object SymDenotations { if (classParents.isEmpty && !emptyParentsExpected) onBehalf.signalProvisional() val builder = new BaseDataBuilder - for (p <- classParents) + for (p <- classParents) { + assert(p.typeSymbol.isClass, s"$this has non-class parent: $p") builder.addAll(p.typeSymbol.asClass.baseClasses) - + } (classSymbol :: builder.baseClasses, builder.baseClassSet) } @@ -1851,20 +1852,18 @@ object SymDenotations { } } - class NoDenotation(sym: Symbol, name: Name, override val exists: Boolean) - extends SymDenotation(sym, NoSymbol, name, Permanent, NoType) { + @sharable object NoDenotation + extends SymDenotation(NoSymbol, NoSymbol, "".toTermName, Permanent, NoType) { override def isType = false - override def isTerm = exists + override def isTerm = false + override def exists = false override def owner: Symbol = throw new AssertionError("NoDenotation.owner") override def computeAsSeenFrom(pre: Type)(implicit ctx: Context): SingleDenotation = this override def mapInfo(f: Type => Type)(implicit ctx: Context): SingleDenotation = this - sym.denot = this + NoSymbol.denot = this validFor = Period.allInRun(NoRunId) } - @sharable val NoDenotation: NoDenotation = - new NoDenotation(NoSymbol, "".toTermName, exists = false) - // ---- Completion -------------------------------------------------------- /** Instances of LazyType are carried by uncompleted symbols. diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index d9a73442ebdd..c37ab584754c 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -451,9 +451,10 @@ object Symbols { final def isValidInCurrentRun(implicit ctx: Context): Boolean = (lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot)) && (lastDenot.symbol eq this) - // the last condition is needed because overwritten package members keep - // denotations pointing to the new symbol, so the validity periods check out OK. - // But once a package member is overridden it is not longerr valid. + // the last condition is needed because under option -Yupdate-stale overwritten + // package members keep denotations pointing to the new symbol, so the validity + // periods check out OK. But once a package member is overridden it is not longer + // valid. If the option would be removed, the check would be no longer needed. final def isTerm(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isTerm @@ -471,14 +472,6 @@ object Symbols { final def isClass: Boolean = isInstanceOf[ClassSymbol] final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] - /** Test whether symbol is referenced symbolically. This - * conservatively returns `false` if symbol does not yet have a denotation - */ - final def isReferencedSymbolically(implicit ctx: Context) = { - val d = lastDenot - d != null && (d.is(NonMember) || ctx.phase.symbolicRefs) - } - /** Test whether symbol is private. This * conservatively returns `false` if symbol does not yet have a denotation, or denotation * is a class that is not yet read. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0fe46fa7363e..b98e48fac6be 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1686,10 +1686,8 @@ object Types { private def loadDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { var d = memberDenot(prefix, name, allowPrivate) - if (!d.exists) { - val d1 = memberDenot(prefix, name, true) - assert(!d1.exists, i"bad allow private $this $name $d1 at ${ctx.phase}") - } + if (!d.exists && ctx.mode.is(Mode.Interactive)) + d = memberDenot(prefix, name, true) if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) // name has changed; try load in earlier phase and make current d = loadDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current @@ -1698,6 +1696,9 @@ object Types { d } + /** Reload denotation by computing the member with the reference's name as seen + * from the reference's prefix. + */ def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))) @@ -1706,7 +1707,7 @@ object Types { private def disambiguate(d: Denotation)(implicit ctx: Context): Denotation = { val sig = currentSignature - //if (ctx.isAfterTyper) println(i"overloaded $this / $d / sig = $sig") + //if (ctx.isAfterTyper) println(i"overloaded $this / $d / sig = $sig") // DEBUG if (sig != null) d.atSignature(sig, relaxed = !ctx.erasedTypes) match { case d1: SingleDenotation => d1 @@ -1900,10 +1901,12 @@ object Types { case _ => withPrefix(prefix) } + /** A reference like this one, but with the given symbol, if it exists */ final def withSym(sym: Symbol)(implicit ctx: Context): ThisType = if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] else this + /** A reference like this one, but with the given denotation, if it exists */ final def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = if (denot.exists) { val adapted = withSym(denot.symbol) @@ -1916,8 +1919,7 @@ object Types { else // don't assign NoDenotation, we might need to recover later. Test case is pos/avoid.scala. this - /** Create a NamedType of the same kind as this type, but with a new prefix. - */ + /** A reference like this one, but with the given prefix. */ final def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = { def reload(): NamedType = { val allowPrivate = !lastSymbol.exists || lastSymbol.is(Private) && prefix.classSymbol == this.prefix.classSymbol @@ -1930,7 +1932,8 @@ object Types { } NamedType(prefix, name, d) } - if (lastDenotation == null) NamedType(prefix, designator) + if (prefix eq this.prefix) this + else if (lastDenotation == null) NamedType(prefix, designator) else designator match { case sym: Symbol => if (infoDependsOnPrefix(sym, prefix)) { diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index abce842998ee..723e659d32fc 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -86,7 +86,7 @@ class ElimErasedValueType extends MiniPhase with InfoTransformer { val site = root.thisType val info1 = site.memberInfo(sym1) val info2 = site.memberInfo(sym2) - def isDefined(sym: Symbol) = sym.lastKnownDenotation.initial.validFor.firstPhaseId <= ctx.phaseId + def isDefined(sym: Symbol) = sym.originDenotation.validFor.firstPhaseId <= ctx.phaseId if (isDefined(sym1) && isDefined(sym2) && !info1.matchesLoosely(info2)) // The reason for the `isDefined` condition is that we need to exclude mixin forwarders // from the tests. For instance, in compileStdLib, compiling scala.immutable.SetProxy, line 29: diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index fe484c5c8c83..61dfd30866d7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -244,7 +244,7 @@ object Checking { locked += tp try checkInfo(tp.info) finally locked -= tp - if (pre1 eq pre) tp else tp.withPrefix(pre1) + tp.withPrefix(pre1) } else tp } catch { diff --git a/tests/pending/pos/t2405.scala b/tests/pending/pos/t2405.scala deleted file mode 100644 index 71627a10bc60..000000000000 --- a/tests/pending/pos/t2405.scala +++ /dev/null @@ -1,23 +0,0 @@ -object A { implicit val x: Int = 1 } - -// Problem as stated in the ticket. -object Test1 { - import A.{x => y} - implicitly[Int] -} - -// Testing for the absense of shadowing #1. -object Test2 { - import A.{x => y} - //val x = 2 - implicitly[Int] -} - -// Testing for the absense of shadowing #2. -object Test3 { - { - import A.{x => y} - def x: Int = 0 - implicitly[Int] - } -} From 6953dfb6d62bb64b5dacf44e1e3d1b3e159548cc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 13:32:21 +0100 Subject: [PATCH 49/58] Make sure bringForward returns a denotation valid in current period There was a scenario in the IDE where this was not the case: If the owner of a denotation was deleted in the new run, the old symbol gets an updated validity. Then, a call to bringForward of a member of that invalid owner will lookup the symbol in its owner, yielding itself. But the validity still was the previous period. --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 96838986c572..917b6845c2da 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -791,7 +791,7 @@ object Denotations { lazy val staleOK = ctx.acceptStale(symd) if (ctx.settings.YupdateStale.value && symd.owner.is(Package) || staleOK) { val newd = symd.owner.info.decls.lookup(symd.name) - if (newd.exists) return newd + if (newd.exists) return (newd.denot: SingleDenotation).updateValidity() else if (staleOK) return updateValidity() } case _ => From 68cd5e66d4f17ad6ff1b44a229d7696aa939de7f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 13:33:15 +0100 Subject: [PATCH 50/58] Handle import aliases of implicit definitions This makes #2405 work again. --- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 14 ++++++++- .../dotty/tools/dotc/typer/Implicits.scala | 29 ++++++++++++------- .../dotty/tools/dotc/typer/ImportInfo.scala | 10 +++++-- tests/pos/t2405.scala | 23 +++++++++++++++ 5 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 tests/pos/t2405.scala diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index d7862a6e7ed1..6b98851f7be6 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -201,7 +201,7 @@ object Contexts { def implicits: ContextualImplicits = { if (implicitsCache == null ) implicitsCache = { - val implicitRefs: List[TermRef] = + val implicitRefs: List[ImplicitDef] = if (isClassDefContext) try owner.thisType.implicitMembers catch { diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b98e48fac6be..8134f841857f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1963,7 +1963,16 @@ object Types { override def eql(that: Type) = this eq that // safe because named types are hash-consed separately } - abstract case class TermRef(override val prefix: Type, var designator: Designator) extends NamedType with SingletonType { + /** A reference to an implicit definition. This can be either a TermRef or a + * Implicits.RenamedImplicitDef. + */ + trait ImplicitDef { + def implicitName(implicit ctx: Context): TermName + def implicitRef: TermRef + } + + abstract case class TermRef(override val prefix: Type, var designator: Designator) + extends NamedType with SingletonType with ImplicitDef { type ThisType = TermRef type ThisName = TermName @@ -1981,6 +1990,9 @@ object Types { def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = denot.altsWith(p).map(withDenot(_)) + + def implicitName(implicit ctx: Context): TermName = name + def implicitRef = this } abstract case class TypeRef(override val prefix: Type, var designator: Designator) extends NamedType { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 94306c08ee31..1ab93878cc1b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -45,11 +45,20 @@ object Implicits { */ val DelayedImplicit = new Property.Key[TermRef] + /** An implicit definition `implicitRef` that is visible under a different name, `alias`. + * Gets generated if an implicit ref is imported via a renaming import. + */ + class RenamedImplicitDef(val implicitRef: TermRef, val alias: TermName) extends ImplicitDef { + def implicitName(implicit ctx: Context): TermName = alias + } + /** An eligible implicit candidate, consisting of an implicit reference and a nesting level */ - case class Candidate(ref: TermRef, level: Int) + case class Candidate(implicitDef: ImplicitDef, level: Int) { + def ref: TermRef = implicitDef.implicitRef + } /** A common base class of contextual implicits and of-type implicits which - * represents a set of implicit references. + * represents a set of references to implicit definitions. */ abstract class ImplicitRefs(initctx: Context) { implicit val ctx: Context = @@ -59,7 +68,7 @@ object Implicits { def level: Int = 0 /** The implicit references */ - def refs: List[TermRef] + def refs: List[ImplicitDef] /** Return those references in `refs` that are compatible with type `pt`. */ protected def filterMatching(pt: Type)(implicit ctx: Context): List[Candidate] = track("filterMatching") { @@ -138,7 +147,7 @@ object Implicits { else { val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext) refs - .filter(ref => nestedCtx.typerState.test(refMatches(ref)(nestedCtx))) + .filter(ref => nestedCtx.typerState.test(refMatches(ref.implicitRef)(nestedCtx))) .map(Candidate(_, level)) } } @@ -150,7 +159,7 @@ object Implicits { */ class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) { assert(initctx.typer != null) - lazy val refs: List[TermRef] = { + lazy val refs: List[ImplicitDef] = { val buf = new mutable.ListBuffer[TermRef] for (companion <- companionRefs) buf ++= companion.implicitMembers buf.toList @@ -176,7 +185,7 @@ object Implicits { * name, b, whereas the name of the symbol is the original name, a. * @param outerCtx the next outer context that makes visible further implicits */ - class ContextualImplicits(val refs: List[TermRef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) { + class ContextualImplicits(val refs: List[ImplicitDef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) { private val eligibleCache = new mutable.AnyRefMap[Type, List[Candidate]] /** The level increases if current context has a different owner or scope than @@ -188,7 +197,7 @@ object Implicits { else if (ctx.scala2Mode || (ctx.owner eq outerImplicits.ctx.owner) && (ctx.scope eq outerImplicits.ctx.scope) && - !refs.head.name.is(LazyImplicitName)) outerImplicits.level + !refs.head.implicitName.is(LazyImplicitName)) outerImplicits.level else outerImplicits.level + 1 /** Is this the outermost implicits? This is the case if it either the implicits @@ -231,8 +240,8 @@ object Implicits { val ownEligible = filterMatching(tp) if (isOuterMost) ownEligible else ownEligible ::: { - val shadowed = ownEligible.map(_.ref.name).toSet - outerImplicits.eligible(tp).filterNot(cand => shadowed.contains(cand.ref.name)) + val shadowed = ownEligible.map(_.ref.implicitName).toSet + outerImplicits.eligible(tp).filterNot(cand => shadowed.contains(cand.ref.implicitName)) } } @@ -818,7 +827,7 @@ trait Implicits { self: Typer => pt) val generated1 = adapt(generated, pt) lazy val shadowing = - typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)( + typed(untpd.Ident(cand.implicitDef.implicitName) withPos pos.toSynthetic, funProto)( nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState()) def refSameAs(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 8b06148a7723..28f917062367 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -9,6 +9,7 @@ import printing.{Printer, Showable} import util.SimpleIdentityMap import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._ import Decorators.StringInterpolators +import Implicits.RenamedImplicitDef object ImportInfo { /** The import info for a root import from given symbol `sym` */ @@ -92,7 +93,7 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], } /** The implicit references imported by this import clause */ - def importedImplicits(implicit ctx: Context): List[TermRef] = { + def importedImplicits(implicit ctx: Context): List[ImplicitDef] = { val pre = site if (isWildcardImport) { val refs = pre.implicitMembers @@ -102,7 +103,12 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], for { renamed <- reverseMapping.keys denot <- pre.member(reverseMapping(renamed)).altsWith(_ is Implicit) - } yield TermRef(pre, renamed, denot) + } yield { + val original = reverseMapping(renamed) + val ref = TermRef(pre, original, denot) + if (renamed == original) ref + else new RenamedImplicitDef(ref, renamed) + } } /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden. diff --git a/tests/pos/t2405.scala b/tests/pos/t2405.scala new file mode 100644 index 000000000000..a4ac914fb803 --- /dev/null +++ b/tests/pos/t2405.scala @@ -0,0 +1,23 @@ +object A { implicit val x: Int = 1 } + +// Problem as stated in the ticket. +object Test1 { + import A.{x => y} + implicitly[Int] +} + +// Testing for the absense of shadowing #1. +object Test2 { + import A.{x => y} + val x = 2 + implicitly[Int] +} + +// Testing for the absense of shadowing #2. +object Test3 { + { + import A.{x => y} + def x: Int = 0 + implicitly[Int] + } +} From f33529c002d7a8560f1d08e0bcde8f03e42d5d7b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 13:37:10 +0100 Subject: [PATCH 51/58] Fix rebase breakage Also: reinstantiate an accidentally deleted test --- .../tools/dotc/core/SymDenotations.scala | 2 +- tests/run/unittest_collection.scala | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/run/unittest_collection.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 27f9e02b5a15..bc3d7abfcf5c 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -417,7 +417,7 @@ object SymDenotations { case name: SimpleName => qualify(name) case name @ AnyQualifiedName(_, _) => qualify(name.mangled.toSimpleName) } - if (name.isType) fn.toTypeName else fn.toTermName + if (name.isTypeName) fn.toTypeName else fn.toTermName } /** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */ diff --git a/tests/run/unittest_collection.scala b/tests/run/unittest_collection.scala new file mode 100644 index 000000000000..8be8ea1a5927 --- /dev/null +++ b/tests/run/unittest_collection.scala @@ -0,0 +1,58 @@ +object Test { + + import scala.collection.mutable.{ArrayBuffer, Buffer, BufferProxy, ListBuffer} + + def main(args: Array[String]): Unit = { + test(collection.mutable.ArrayBuffer[String]()) + test(collection.mutable.ListBuffer[String]()) + class BBuf(z:ListBuffer[String]) extends BufferProxy[String] { // @odersky - bug here in scala 2.12 trait encoding seems like... + def self = z + } + test(new BBuf(collection.mutable.ListBuffer[String]())) + } + + def test(x: Buffer[String]): Unit = { + // testing method += + x += "one" + assert(x(0) == "one", "retrieving 'one'") + assert(x.length == 1, "length A") + x += "two" + assert(x(1) == "two", "retrieving 'two'") + assert(x.length == 2, "length B") + + // testing method -= (removing last element) + x -= "two" + + assert(x.length == 1, "length C") + + try { x(1); sys.error("no exception for removed element") } + catch { case i:IndexOutOfBoundsException => } + + try { x.remove(1); sys.error("no exception for removed element") } + catch { case i:IndexOutOfBoundsException => } + + x += "two2" + assert(x.length == 2, "length D") + + // removing first element + x.remove(0) + assert(x.length == 1, "length E") + + // toList + assert(x.toList == List("two2"), "toList") + + // clear + x.clear() + assert(x.length == 0, "length 0") + assert(x.isEmpty, "isEmpty") + + // copyToBuffer + x += "a" + x += "b" + val dest = new ArrayBuffer[String] + x.copyToBuffer(dest) + assert(List("a", "b") == dest.toList, "dest") + assert(List("a", "b") == x.toList, "source") + } + +} From c81f28275f6e6a6e3ea7afffea81975c04fa4d84 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 13:50:11 +0100 Subject: [PATCH 52/58] Rename ImplicitDef -> ImplicitRef --- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 10 +++++----- .../src/dotty/tools/dotc/typer/Implicits.scala | 16 ++++++++-------- .../src/dotty/tools/dotc/typer/ImportInfo.scala | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 6b98851f7be6..439c04d502a0 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -201,7 +201,7 @@ object Contexts { def implicits: ContextualImplicits = { if (implicitsCache == null ) implicitsCache = { - val implicitRefs: List[ImplicitDef] = + val implicitRefs: List[ImplicitRef] = if (isClassDefContext) try owner.thisType.implicitMembers catch { diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8134f841857f..cb0c6edd18bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1964,15 +1964,15 @@ object Types { } /** A reference to an implicit definition. This can be either a TermRef or a - * Implicits.RenamedImplicitDef. + * Implicits.RenamedImplicitRef. */ - trait ImplicitDef { + trait ImplicitRef { def implicitName(implicit ctx: Context): TermName - def implicitRef: TermRef + def underlyingRef: TermRef } abstract case class TermRef(override val prefix: Type, var designator: Designator) - extends NamedType with SingletonType with ImplicitDef { + extends NamedType with SingletonType with ImplicitRef { type ThisType = TermRef type ThisName = TermName @@ -1992,7 +1992,7 @@ object Types { denot.altsWith(p).map(withDenot(_)) def implicitName(implicit ctx: Context): TermName = name - def implicitRef = this + def underlyingRef = this } abstract case class TypeRef(override val prefix: Type, var designator: Designator) extends NamedType { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 1ab93878cc1b..259fb1048cf4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -48,13 +48,13 @@ object Implicits { /** An implicit definition `implicitRef` that is visible under a different name, `alias`. * Gets generated if an implicit ref is imported via a renaming import. */ - class RenamedImplicitDef(val implicitRef: TermRef, val alias: TermName) extends ImplicitDef { + class RenamedImplicitRef(val underlyingRef: TermRef, val alias: TermName) extends ImplicitRef { def implicitName(implicit ctx: Context): TermName = alias } /** An eligible implicit candidate, consisting of an implicit reference and a nesting level */ - case class Candidate(implicitDef: ImplicitDef, level: Int) { - def ref: TermRef = implicitDef.implicitRef + case class Candidate(implicitRef: ImplicitRef, level: Int) { + def ref: TermRef = implicitRef.underlyingRef } /** A common base class of contextual implicits and of-type implicits which @@ -68,7 +68,7 @@ object Implicits { def level: Int = 0 /** The implicit references */ - def refs: List[ImplicitDef] + def refs: List[ImplicitRef] /** Return those references in `refs` that are compatible with type `pt`. */ protected def filterMatching(pt: Type)(implicit ctx: Context): List[Candidate] = track("filterMatching") { @@ -147,7 +147,7 @@ object Implicits { else { val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext) refs - .filter(ref => nestedCtx.typerState.test(refMatches(ref.implicitRef)(nestedCtx))) + .filter(ref => nestedCtx.typerState.test(refMatches(ref.underlyingRef)(nestedCtx))) .map(Candidate(_, level)) } } @@ -159,7 +159,7 @@ object Implicits { */ class OfTypeImplicits(tp: Type, val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) { assert(initctx.typer != null) - lazy val refs: List[ImplicitDef] = { + lazy val refs: List[ImplicitRef] = { val buf = new mutable.ListBuffer[TermRef] for (companion <- companionRefs) buf ++= companion.implicitMembers buf.toList @@ -185,7 +185,7 @@ object Implicits { * name, b, whereas the name of the symbol is the original name, a. * @param outerCtx the next outer context that makes visible further implicits */ - class ContextualImplicits(val refs: List[ImplicitDef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) { + class ContextualImplicits(val refs: List[ImplicitRef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) { private val eligibleCache = new mutable.AnyRefMap[Type, List[Candidate]] /** The level increases if current context has a different owner or scope than @@ -827,7 +827,7 @@ trait Implicits { self: Typer => pt) val generated1 = adapt(generated, pt) lazy val shadowing = - typed(untpd.Ident(cand.implicitDef.implicitName) withPos pos.toSynthetic, funProto)( + typed(untpd.Ident(cand.implicitRef.implicitName) withPos pos.toSynthetic, funProto)( nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState()) def refSameAs(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 28f917062367..596a6092bd5d 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -9,7 +9,7 @@ import printing.{Printer, Showable} import util.SimpleIdentityMap import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._ import Decorators.StringInterpolators -import Implicits.RenamedImplicitDef +import Implicits.RenamedImplicitRef object ImportInfo { /** The import info for a root import from given symbol `sym` */ @@ -93,7 +93,7 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], } /** The implicit references imported by this import clause */ - def importedImplicits(implicit ctx: Context): List[ImplicitDef] = { + def importedImplicits(implicit ctx: Context): List[ImplicitRef] = { val pre = site if (isWildcardImport) { val refs = pre.implicitMembers @@ -107,7 +107,7 @@ class ImportInfo(symf: Context => Symbol, val selectors: List[untpd.Tree], val original = reverseMapping(renamed) val ref = TermRef(pre, original, denot) if (renamed == original) ref - else new RenamedImplicitDef(ref, renamed) + else new RenamedImplicitRef(ref, renamed) } } From 6ff60daa4afb6686939ba09f47b1839c8f809d34 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 13:50:25 +0100 Subject: [PATCH 53/58] More tests --- tests/pickling/i3479.scala | 10 ++++ tests/pickling/ops.scala | 7 +++ tests/run/nats.scala | 40 ++++++++++++++++ tests/run/nats.scala-deptypes | 89 +++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 tests/pickling/i3479.scala create mode 100644 tests/pickling/ops.scala create mode 100644 tests/run/nats.scala create mode 100644 tests/run/nats.scala-deptypes diff --git a/tests/pickling/i3479.scala b/tests/pickling/i3479.scala new file mode 100644 index 000000000000..338674ee329a --- /dev/null +++ b/tests/pickling/i3479.scala @@ -0,0 +1,10 @@ +sealed trait TermConstraint { + final def neg: TermConstraint = this match { + case Neg(c) => c + case c: PositiveTermConstraint => Neg(c) + } +} +case class Neg(c: PositiveTermConstraint) extends TermConstraint +sealed trait PositiveTermConstraint extends TermConstraint + +case object Dummy extends PositiveTermConstraint diff --git a/tests/pickling/ops.scala b/tests/pickling/ops.scala new file mode 100644 index 000000000000..b2c6a3855d8c --- /dev/null +++ b/tests/pickling/ops.scala @@ -0,0 +1,7 @@ +object Test { + + val num = implicitly[Integral[Int]] + val ops = num.mkOrderingOps + ops(9) < 10 + +} diff --git a/tests/run/nats.scala b/tests/run/nats.scala new file mode 100644 index 000000000000..bb0b9c85b9a8 --- /dev/null +++ b/tests/run/nats.scala @@ -0,0 +1,40 @@ +abstract class Nat { + def toInt: Int +} +object Nat { + case class S[N <: Nat](pred: N) extends Nat { + def toInt = pred.toInt + 1 + } + class Z extends Nat { + def toInt = 0 + } + val Z = new Z +} + +trait Plus[X <: Nat, Y <: Nat, R <: Nat] { + def add(x: X, y: Y): R +} + +object Test { + import Nat._ + implicit def zPlus[Y <: Nat]: Plus[Z, Y, Y] = new { + def add(x: Z, y: Y): Y = y + } + implicit def sPlus[X <: Nat, Y <: Nat, R <: Nat]( + implicit ev: Plus[X, Y, R] + ): Plus[S[X], Y, S[R]] = new { + def add(x: S[X], y: Y): S[R] = S(ev.add(x.pred, y)) + } + def plus[X <: Nat, Y <: Nat, R <: Nat](x: X, y: Y)( + implicit ev: Plus[X, Y, R] + ): R = ev.add(x, y) + def main(args: Array[String]) = { + val x = S(S(Z)) + val x1: S[S[Z]] = x + val y = S(Z) + val z = plus(x, y) + val z1: S[S[S[Z]]] = z + println(z.toInt) + } +} + diff --git a/tests/run/nats.scala-deptypes b/tests/run/nats.scala-deptypes new file mode 100644 index 000000000000..80b68336d7e3 --- /dev/null +++ b/tests/run/nats.scala-deptypes @@ -0,0 +1,89 @@ +abstract class Nat { + def toInt: Int +} +object Nat { + case class S[N <: Nat](pred: N) extends Nat { + def toInt = pred.toInt + 1 + } + class Z extends Nat { + def toInt = 0 + } + val Z = new Z +} + +type NatOf(inline x: Int where x >= 0) = + if (x == 0) Z + else S[NatOf(x - 1)] + +inline def natOf(inline x: Int where x >= 0): NatOf(x) = + if (x == 0) Z + else S(natOf(x - 1)) + + + + + +type Plus[X <: Nat, Y <: Nat] = + if [X <:< Z] then Y + else if [X <:< S[type X1]] then S[Plus[X1, Y]] + +object Test { + import Nat._ + def plus[X <: Nat, Y <: Nat](x: X, y: Y): Plus[X, Y] = + if [X <:< Z] then y + else if [X <:< S[_]] then S(plus(x.pred, y)) + + // Expanded version of `plus`: + def plus2[X <: Nat, Y <: Nat](x: X, y: Y): Plus[X, Y] = + if [X <:< Z] y + else if [implicit ev: X <:< S[_]] then S(plus(ev(x).pred, y)) + + // This typechecks as follows: + + // X <:< S[_] + // X <:< S[T'] for some T' <: Nat + // => ev(x): S[T'] + // => ev(x).pred: T' + // => plus(ev(x).pred, y): Plus[T', Y] + // => S(plus(ev(x).pred, y)): S[Plus[T', Y]] + + // X <:< S[T'] + // => Plus[X, Y] = S[Plus[T', Y]] + + // Expanded version of `plus`: + def plus3[X <:< Nat, Y <:< Nat](x: Nat, y: Nat): Plus[x.type, y.type] = x match { + case (x: Z) => y + case S(x1) => S(plus(x1, y)) + } + + + + + // x: Z + // => x.type <:< Z + // => Plus[x.type, y.type] = y.type + + // x =?= S(x1) + // => x.type <: S[T1], s1: T1 + // => plus(x1, y): Plus[T1, y.type] + // => + + + def main(args: Array[String]) = { + val x = S(S(Z)) + val x1: S[S[Z]] = x + val y = S(Z) + val z = plus(x, y) + val z1: S[S[S[Z]]] = z + println(z.toInt) + } + + type Concat[X <: Tuple, Y <: Tuple] = + if [X <:< ()] then Y + else if [X <:< (type F, type R)] then (F, Concat[R, Y]) + + def concat[X <: Tuple, Y <: Tuple](x: X, y: Y): Concat[X, Y] = + if [X <:< ()] then Y + else if [X <:< (type F, type R)] then (x.head, concat(x.tail, y)) +} + From 8578fa139ac843a03fd4d3f64c071af81c972e39 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 17:43:58 +0100 Subject: [PATCH 54/58] Add original test that caused the whole rewrite --- tests/pos/i3488.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/pos/i3488.scala diff --git a/tests/pos/i3488.scala b/tests/pos/i3488.scala new file mode 100644 index 000000000000..762ec4b7df30 --- /dev/null +++ b/tests/pos/i3488.scala @@ -0,0 +1,16 @@ +package test + +class Sett[A] { + + def incl(elem: A): Sett[A] = ??? + + inline final def + (elem: A): Sett[A] = incl(elem) +} + +object Sett { + def apply[A](elems: A*): Sett[A] = ??? +} + +class Test { + Sett(1) + 1 +} From dd9581720b57ae59dde11fff0a879026bf23df88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 27 Nov 2017 19:22:51 +0100 Subject: [PATCH 55/58] Fix rebase breakage --- compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index ddf7f946a68e..505f68d28007 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -366,7 +366,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case _ => toText(name) } - if (name.isType) typeText(txt) + if (name.isTypeName) typeText(txt) else txt case tree @ Select(qual, name) => if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name)) From eb9311256734cd487d438438d0efdee1ce1f7a65 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 28 Nov 2017 14:52:24 +0100 Subject: [PATCH 56/58] Harden IDE In interactive mode, allow uncompleted symbols with completers from previous runs. This is possible due to the way we bring forwward stale symbols. Liek in manual cleanup in InteractiveDriver, we set the info of such symbols to UnspecifiedError. --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 917b6845c2da..cfdbf017f555 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -761,7 +761,7 @@ object Denotations { def invalidateInheritedInfo(): Unit = () private def updateValidity()(implicit ctx: Context): this.type = { - assert(ctx.runId > validFor.runId || ctx.settings.YtestPickler.value, // mixing test pickler with debug printing can travel back in time + assert(ctx.runId >= validFor.runId || ctx.settings.YtestPickler.value, // mixing test pickler with debug printing can travel back in time s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor") var d: SingleDenotation = this do { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 4c4a6dbd9acd..94b581d999b0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -754,8 +754,11 @@ class Namer { typer: Typer => else levels(c.outer) + 1 println(s"!!!completing ${denot.symbol.showLocated} in buried typerState, gap = ${levels(ctx)}") } - assert(ctx.runId == creationContext.runId, s"completing $denot in wrong run ${ctx.runId}, was created in ${creationContext.runId}") - completeInCreationContext(denot) + if (ctx.runId > creationContext.runId) { + assert(ctx.mode.is(Mode.Interactive), s"completing $denot in wrong run ${ctx.runId}, was created in ${creationContext.runId}") + denot.info = UnspecifiedErrorType + } + else completeInCreationContext(denot) } private def addInlineInfo(denot: SymDenotation) = original match { From 2524788f4a7d42dc9bd158cc24c071d10e2a9ff9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 29 Nov 2017 09:09:06 +0100 Subject: [PATCH 57/58] Some renamings --- .../src/dotty/tools/dotc/core/Types.scala | 62 +++++++++---------- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index cb0c6edd18bb..54b6d344dd2e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1174,7 +1174,7 @@ object Types { tycon.parents.map(_.subst(tycon.typeSymbol.typeParams, args)) case tp: TypeRef => if (tp.info.isInstanceOf[TempClassInfo]) { - tp.reloadDenot() + tp.recomputeDenot() assert(!tp.info.isInstanceOf[TempClassInfo]) } tp.info.parents @@ -1633,7 +1633,7 @@ object Types { def finish(d: Denotation) = { if (ctx.typerState.ephemeral) - record("ephemeral cache miss: loadDenot") + record("ephemeral cache miss: memberDenot") else if (d.exists) // Avoid storing NoDenotations in the cache - we will not be able to recover from // them. The situation might arise that a type has NoDenotation in some later @@ -1648,13 +1648,13 @@ object Types { case name: Name => val sym = lastSymbol val allowPrivate = sym == null || (sym == NoSymbol) || sym.lastKnownDenotation.flagsUNSAFE.is(Private) - finish(loadDenot(name, allowPrivate)) + finish(memberDenot(name, allowPrivate)) case sym: Symbol => val symd = sym.lastKnownDenotation if (symd.validFor.runId != ctx.runId && !ctx.stillValid(symd)) - finish(loadDenot(symd.initial.name, allowPrivate = false)) + finish(memberDenot(symd.initial.name, allowPrivate = false)) else if (infoDependsOnPrefix(symd, prefix)) - finish(loadDenot(symd.initial.name, allowPrivate = symd.is(Private))) + finish(memberDenot(symd.initial.name, allowPrivate = symd.is(Private))) else finish(symd.current) } @@ -1669,13 +1669,7 @@ object Types { else lastd match { case lastd: SymDenotation => if (ctx.stillValid(lastd)) finish(lastd.current) - else - try finish(loadDenot(lastd.initial.name, allowPrivate = false)) - catch { - case ex: AssertionError => - println(i"assertion failed while $this . $lastd . ${lastd.validFor} ${lastd.flagsUNSAFE}") - throw ex - } + else finish(memberDenot(lastd.initial.name, allowPrivate = false)) case _ => fromDesignator } @@ -1684,27 +1678,6 @@ object Types { finally ctx.typerState.ephemeral |= savedEphemeral } - private def loadDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { - var d = memberDenot(prefix, name, allowPrivate) - if (!d.exists && ctx.mode.is(Mode.Interactive)) - d = memberDenot(prefix, name, true) - if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) - // name has changed; try load in earlier phase and make current - d = loadDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current - if (d.isOverloaded) - d = disambiguate(d) - d - } - - /** Reload denotation by computing the member with the reference's name as seen - * from the reference's prefix. - */ - def reloadDenot()(implicit ctx: Context) = - setDenot(loadDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))) - - private def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = - if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) - private def disambiguate(d: Denotation)(implicit ctx: Context): Denotation = { val sig = currentSignature //if (ctx.isAfterTyper) println(i"overloaded $this / $d / sig = $sig") // DEBUG @@ -1720,6 +1693,27 @@ object Types { else d } + private def memberDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { + var d = memberDenot(prefix, name, allowPrivate) + if (!d.exists && ctx.mode.is(Mode.Interactive)) + d = memberDenot(prefix, name, true) + if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) + // name has changed; try load in earlier phase and make current + d = memberDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current + if (d.isOverloaded) + d = disambiguate(d) + d + } + + private def memberDenot(prefix: Type, name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = + if (allowPrivate) prefix.member(name) else prefix.nonPrivateMember(name) + + /** Reload denotation by computing the member with the reference's name as seen + * from the reference's prefix. + */ + def recomputeDenot()(implicit ctx: Context) = + setDenot(memberDenot(name, allowPrivate = !symbol.exists || symbol.is(Private))) + private def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { if (ctx.isAfterTyper) assert(!denot.isOverloaded, this) @@ -3745,7 +3739,7 @@ object Types { def apply(tp: Type): Type protected def derivedSelect(tp: NamedType, pre: Type): Type = - tp.derivedSelect(pre) match { + tp.derivedSelect(pre) match { case tp: TypeArgRef if variance != 0 => val tp1 = tp.underlying if (variance > 0) tp1.hiBound else tp1.loBound diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 94b581d999b0..9db27eddc9f7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1203,7 +1203,7 @@ class Namer { typer: Typer => // fail with a bounds error in PostTyper. def ensureUpToDate(tp: Type, outdated: Type) = tp match { case tref: TypeRef if tref.info == outdated && sym.info != outdated => - tref.reloadDenot() + tref.recomputeDenot() case _ => } ensureUpToDate(sym.typeRef, dummyInfo) From 759af1e995b2ba9fd9d81ca6ccd79002a94a88b3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Dec 2017 13:03:59 +0100 Subject: [PATCH 58/58] Adress reviewers comments Major changes - Drop -Yupdate-stale and simplify bringForward accordingly - Make designator a private field of TypeRef and TermRef --- .../tools/dotc/config/ScalaSettings.scala | 1 - .../dotty/tools/dotc/core/Denotations.scala | 10 +++----- .../tools/dotc/core/SymDenotations.scala | 5 +++- .../src/dotty/tools/dotc/core/Symbols.scala | 4 ++-- .../src/dotty/tools/dotc/core/Types.scala | 23 +++++++++++++++---- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 48ccc7528312..e4f3137458ef 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -106,7 +106,6 @@ class ScalaSettings extends Settings.SettingGroup { val YkeepComments = BooleanSetting("-Ykeep-comments", "Keep comments when scanning source files.") val YforceSbtPhases = BooleanSetting("-Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.") val YdumpSbtInc = BooleanSetting("-Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.") - val YupdateStale = BooleanSetting("-Yupdate-stale", "Automically update stale top-level classes and objects to latest version") val YcheckAllPatmat = BooleanSetting("-Ycheck-all-patmat", "Check exhaustivity and redundancy of all pattern matching (used for testing the algorithm)") val YretainTrees = BooleanSetting("-Yretain-trees", "Retain trees for top-level classes, accessible from ClassSymbol#tree") val YshowTreeIds = BooleanSetting("-Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.") diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index cfdbf017f555..bf82ca9384b4 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -776,9 +776,7 @@ object Denotations { * if denotation is no longer valid. * However, StaleSymbol error is not thrown in the following situations: * - * - If the symbol is a toplevel class or object and -Yupdate-stale is set. - * update the denotation to the new symbol with the same name instead. - * - If ctx.acceptStale returns true (because we are in the IDE), + * - If ctx.acceptStale returns true (e.g. because we are in the IDE), * update the symbol to the new version if it exists, or return * the old version otherwise. * - If the symbol did not have a denotation that was defined at the current phase @@ -788,11 +786,9 @@ object Denotations { this match { case symd: SymDenotation => if (ctx.stillValid(symd)) return updateValidity() - lazy val staleOK = ctx.acceptStale(symd) - if (ctx.settings.YupdateStale.value && symd.owner.is(Package) || staleOK) { + if (ctx.acceptStale(symd)) { val newd = symd.owner.info.decls.lookup(symd.name) - if (newd.exists) return (newd.denot: SingleDenotation).updateValidity() - else if (staleOK) return updateValidity() + return (newd.denot: SingleDenotation).orElse(symd).updateValidity() } case _ => } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index bc3d7abfcf5c..1fa9313f6c90 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -102,8 +102,11 @@ trait SymDenotations { this: Context => } /** Configurable: Accept stale symbol with warning if in IDE */ + def staleOK = Config.ignoreStaleInIDE && mode.is(Mode.Interactive) + + /** Possibly accept stale symbol with warning if in IDE */ def acceptStale(denot: SingleDenotation): Boolean = - mode.is(Mode.Interactive) && Config.ignoreStaleInIDE && { + staleOK && { ctx.echo(denot.staleSymbolMsg) true } diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index c37ab584754c..031146a80924 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -451,8 +451,8 @@ object Symbols { final def isValidInCurrentRun(implicit ctx: Context): Boolean = (lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot)) && (lastDenot.symbol eq this) - // the last condition is needed because under option -Yupdate-stale overwritten - // package members keep denotations pointing to the new symbol, so the validity + // the last condition is needed because under ctx.staleOK overwritten + // members keep denotations pointing to the new symbol, so the validity // periods check out OK. But once a package member is overridden it is not longer // valid. If the option would be removed, the check would be no longer needed. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 54b6d344dd2e..4dc96f727f61 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1695,7 +1695,8 @@ object Types { private def memberDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { var d = memberDenot(prefix, name, allowPrivate) - if (!d.exists && ctx.mode.is(Mode.Interactive)) + if (!d.exists && !allowPrivate && ctx.mode.is(Mode.Interactive)) + // In the IDE we might change a public symbol to private, and would still expect to find it. d = memberDenot(prefix, name, true) if (!d.exists && ctx.phaseId > FirstPhaseId && lastDenotation.isInstanceOf[SymDenotation]) // name has changed; try load in earlier phase and make current @@ -1900,7 +1901,10 @@ object Types { if ((designator ne sym) && sym.exists) NamedType(prefix, sym).asInstanceOf[ThisType] else this - /** A reference like this one, but with the given denotation, if it exists */ + /** A reference like this one, but with the given denotation, if it exists. + * If the symbol of `denot` is the same as the current symbol, the denotation + * is re-used, otherwise a new one is created. + */ final def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = if (denot.exists) { val adapted = withSym(denot.symbol) @@ -1965,12 +1969,16 @@ object Types { def underlyingRef: TermRef } - abstract case class TermRef(override val prefix: Type, var designator: Designator) - extends NamedType with SingletonType with ImplicitRef { + abstract case class TermRef(override val prefix: Type, + private var myDesignator: Designator) + extends NamedType with SingletonType with ImplicitRef { type ThisType = TermRef type ThisName = TermName + override def designator = myDesignator + override protected def designator_=(d: Designator) = myDesignator = d + //assert(name.toString != "") override def underlying(implicit ctx: Context): Type = { val d = denot @@ -1989,11 +1997,16 @@ object Types { def underlyingRef = this } - abstract case class TypeRef(override val prefix: Type, var designator: Designator) extends NamedType { + abstract case class TypeRef(override val prefix: Type, + private var myDesignator: Designator) + extends NamedType { type ThisType = TypeRef type ThisName = TypeName + override def designator = myDesignator + override protected def designator_=(d: Designator) = myDesignator = d + override def underlying(implicit ctx: Context): Type = info }