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) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 334e2a467476..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) } @@ -709,7 +709,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val tp = if (sym.isType) { assert(!sym.is(TypeParam)) - TypeRef(tree.tpe, sym.name.asTypeName) + TypeRef(tree.tpe, sym.asType) } else TermRef(tree.tpe, sym.name.asTermName, sym.denot.asSeenFrom(tree.tpe)) @@ -718,8 +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(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 @@ -927,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/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index d7862a6e7ed1..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[TermRef] = + val implicitRefs: List[ImplicitRef] = if (isClassDefContext) try owner.thisType.implicitMembers catch { diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 026f3ceae6cf..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 @@ -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 @@ -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 c3294acc1621..bf82ca9384b4 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 @@ -200,7 +282,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 +292,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 @@ -547,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 { @@ -693,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 @@ -714,26 +760,42 @@ 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. + * However, StaleSymbol error is not thrown in the following situations: + * + * - 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 + * return a NoDenotation instead. */ - 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 - case _ => - 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 (ctx.acceptStale(symd)) { + val newd = symd.owner.info.decls.lookup(symd.name) + return (newd.denot: SingleDenotation).orElse(symd).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 @@ -750,6 +812,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). @@ -973,13 +1041,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 = @@ -998,7 +1066,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)) } @@ -1064,115 +1132,108 @@ 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) } - // --------------- 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 ------------------------------- 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/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/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 } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ca7a889affeb..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 } @@ -417,7 +420,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. */ @@ -566,7 +569,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? */ @@ -772,7 +775,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) @@ -1134,10 +1136,10 @@ object SymDenotations { def thisType(implicit ctx: Context): Type = NoPrefix override def typeRef(implicit ctx: Context): TypeRef = - TypeRef(owner.thisType, name.asTypeName, this) + TypeRef(owner.thisType, symbol) override def termRef(implicit ctx: Context): TermRef = - 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 @@ -1405,7 +1407,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 @@ -1439,7 +1441,7 @@ object SymDenotations { onBehalf.signalProvisional() val builder = new BaseDataBuilder for (p <- classParents) { - assert(p.typeSymbol.isClass, s"$this has $p") + assert(p.typeSymbol.isClass, s"$this has non-class parent: $p") builder.addAll(p.typeSymbol.asClass.baseClasses) } (classSymbol :: builder.baseClasses, builder.baseClassSet) @@ -1488,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 } } @@ -1677,7 +1681,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 { @@ -1845,26 +1849,24 @@ 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 } } - class NoDenotation extends SymDenotation( - NoSymbol, NoSymbol, "".toTermName, Permanent, NoType) { - override def exists = false - override def isTerm = false + @sharable object NoDenotation + extends SymDenotation(NoSymbol, NoSymbol, "".toTermName, Permanent, NoType) { override def isType = false + 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 + NoSymbol.denot = this validFor = Period.allInRun(NoRunId) } - @sharable val NoDenotation = new NoDenotation - // ---- 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 85ef64c237ca..031146a80924 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,7 +157,7 @@ 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) TypeRef(owner.thisType, modcls) else new ModuleCompleter(modcls)) module.denot = mdenot modcls.denot = cdenot @@ -183,7 +182,7 @@ 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, TermRef(owner.thisType, module)), privateWithin, coord, assocFile) val companionMethodFlags = Flags.Synthetic | Flags.Private | Flags.Method @@ -291,7 +290,7 @@ trait Symbols { this: Context => for (name <- names) { val tparam = newNakedSymbol[TypeName](NoCoord) tparamBuf += tparam - trefBuf += TypeRef.withSym(owner.thisType, tparam, name) + trefBuf += TypeRef(owner.thisType, tparam) } val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) @@ -303,7 +302,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) @@ -432,10 +431,14 @@ object Symbols { newd } - /** The initial denotation of this symbol, without going through `current` */ - final def initialDenot(implicit ctx: Context): SymDenotation = + /** 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 + private[core] def defRunId: RunId = if (lastDenot == null) NoRunId else lastDenot.validFor.runId @@ -444,19 +447,24 @@ 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) - - /** Designator overrides */ - final override def isTerm(implicit ctx: Context): Boolean = + (lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot)) && + (lastDenot.symbol eq this) + // 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. + + 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] } @@ -464,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) || d.isTerm && 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. @@ -490,7 +490,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 @@ -648,12 +648,13 @@ object Symbols { denot = underlying.denot } - @sharable object NoSymbol extends Symbol(NoCoord, 0) { - denot = NoDenotation + @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 } + 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 */ def copy( diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index eec7130675e8..904b4fe1ad65 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 _ => @@ -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/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/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 faa349c911e5..4dc96f727f61 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 @@ -710,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 */ @@ -1134,15 +1133,21 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = - NamedType(this, name).reduceProjection + NamedType(this, name, member(name)).reduceProjection - /** The type , reduced if possible, with given denotation if unreduced */ + /** 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.withSym(this, sym).reduceProjection + NamedType(this, sym).reduceProjection + + def select(name: TermName)(implicit ctx: Context): TermRef = + 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)) // ----- Access to parts -------------------------------------------- @@ -1169,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 @@ -1497,65 +1502,83 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ - type NameSpace = TypeRef /* | Null */ - @sharable val noNameSpace: NameSpace = null - - /** 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 - val designator: Designator { type ThisName = self.ThisName } + 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 + 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 = { - 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 + /** 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] } - final def name(implicit ctx: Context): ThisName = { - if (myName == null) myName = designator.asInstanceOf[Symbol].name.asInstanceOf[ThisName] - myName + private def computeName: Name = designator match { + case name: Name => 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 = denot.signature + if (mySig == null) mySig = computeSignature mySig } - final def nameSpace: NameSpace = myNameSpace + def computeSignature(implicit ctx: Context): Signature = { + val lastd = lastDenotation + if (lastd != null) lastd.signature + else symbol.asSeenFrom(prefix).signature + } - private[this] var lastDenotation: Denotation = _ - private[this] var lastSymbol: Symbol = _ - private[this] var checkedPeriod = Nowhere + /** 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 { + val lastd = lastDenotation + if (lastd != null) lastd.signature + else { + val sym = currentSymbol + if (sym.exists) sym.asSeenFrom(prefix).signature + else Signature.NotAMethod + } + } - // Invariants: - // (1) checkedPeriod != Nowhere => lastDenotation != null - // (2) lastDenotation != null => lastSymbol != null + final 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 + } /** There is a denotation computed which is valid (somewhere in) the * current run. @@ -1563,7 +1586,7 @@ object Types { def denotationIsCurrent(implicit ctx: Context) = lastDenotation != null && lastDenotation.validFor.runId == ctx.runId - /** The denotation is current, its symbol, otherwise NoDenotation. + /** 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 @@ -1572,8 +1595,21 @@ 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) = - if (denotationIsCurrent) symbol else NoSymbol + final def currentSymbol(implicit ctx: Context) = designator match { + case sym: Symbol => sym + case _ => if (denotationIsCurrent) lastDenotation.symbol else NoSymbol + } + + /** 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 = { + if (checkedPeriod.runId == ctx.runId) lastSymbol + else symbol + } + + def info(implicit ctx: Context): Type = denot.info /** The denotation currently denoted by this type */ final def denot(implicit ctx: Context): Denotation = { @@ -1593,94 +1629,112 @@ object Types { else computeDenot } - /** Hook for adding debug check code when denotations are assigned */ - final 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 */ private def computeDenot(implicit ctx: Context): Denotation = { - val savedEphemeral = ctx.typerState.ephemeral - ctx.typerState.ephemeral = false - try { - val d = lastDenotation match { - case null => - 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 || - d.exists && prefix.isTightPrefix(d.owner) || - d.isConstructor) d.current - else - recomputeMember(d) // symbol could have been overridden, recompute membership - else { - val newd = loadDenot - if (newd.exists) newd - else if (ctx.mode.is(Mode.Interactive)) d - else d.staleSymbolError - } - 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) { + + def finish(d: Denotation) = { + if (ctx.typerState.ephemeral) + 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 // 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() - } + 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(memberDenot(name, allowPrivate)) + case sym: Symbol => + val symd = sym.lastKnownDenotation + if (symd.validFor.runId != ctx.runId && !ctx.stillValid(symd)) + finish(memberDenot(symd.initial.name, allowPrivate = false)) + else if (infoDependsOnPrefix(symd, prefix)) + finish(memberDenot(symd.initial.name, allowPrivate = symd.is(Private))) + else + finish(symd.current) + } + + val savedEphemeral = ctx.typerState.ephemeral + ctx.typerState.ephemeral = false + try + lastDenotation match { + 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(memberDenot(lastd.initial.name, allowPrivate = false)) + case _ => + fromDesignator + } + case _ => fromDesignator + } 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 = - 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 - } - } + private def disambiguate(d: Denotation)(implicit ctx: Context): Denotation = { + val sig = currentSignature + //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 + case d1 => + d1.atSignature(sig, relaxed = false) match { + case d2: SingleDenotation => d2 + case d2 => d2.suchThat(currentSymbol.eq).orElse(d2) + } + } + else d + } + + private def memberDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { + var d = memberDenot(prefix, name, allowPrivate) + 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 + d = memberDenot(name, allowPrivate)(ctx.withPhase(ctx.phaseId - 1)).current + if (d.isOverloaded) + d = disambiguate(d) + d + } - private def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = { - val d = sym.denot - val owner = d.owner - if (owner.isTerm) d else d.asSeenFrom(prefix) + 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) + if (Config.checkNoDoubleBindings) + if (ctx.settings.YnoDoubleBindings.value) + checkSymAssign(denot.symbol) + + 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() } + private def checkDenot()(implicit ctx: Context) = {} + private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = { def selfTypeOf(sym: Symbol) = if (sym.isClass) sym.asClass.givenSelfType else NoType @@ -1688,14 +1742,8 @@ object Types { (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] || @@ -1707,84 +1755,27 @@ 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}""") } - private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { - val adapted = - if (hasFixedSym) - this - else if (signature != denot.signature) - withSig(denot.signature) - else if (denot.symbol.isPrivate) - withNameSpace(denot.symbol.owner.typeRef) - else - this - if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType] - else { - setDenot(denot) - this - } - } - - private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = { - 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 - } - - private[dotc] def withSym(sym: Symbol)(implicit ctx: Context): this.type = { - setSym(sym) - this - } - - private[dotc] final def setSym(sym: Symbol)(implicit ctx: Context): Unit = { - if (Config.checkNoDoubleBindings) - if (ctx.settings.YnoDoubleBindings.value) - checkSymAssign(sym) - uncheckedSetSym(sym) - } - - private[dotc] final def uncheckedSetSym(sym: Symbol): Unit = { - lastDenotation = null - lastSymbol = sym - checkedPeriod = Nowhere - } - - private def withSig(sig: Signature)(implicit ctx: Context): NamedType = - TermRef(prefix, designator.withSig(sig)) + /** 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) - protected def loadDenot(implicit ctx: Context): Denotation = { - val d = asMemberOf(prefix, allowPrivate = false) - if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (mySig != null && mySig.ne(Signature.OverloadedSignature)) d.atSignature(mySig).checkUnique - 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") - } + /** 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 reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) - - protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = - 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. * @@ -1799,23 +1790,6 @@ object Types { } else this - def symbol(implicit ctx: Context): Symbol = - 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 = - 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: @@ -1843,8 +1817,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`. */ @@ -1894,7 +1866,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) @@ -1924,15 +1896,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 + /** 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 - /** Create a NamedType of the same kind as this type, but with a new namespace. + /** 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. */ - def withNameSpace(nameSpace: NameSpace)(implicit ctx: Context): NamedType = - if (nameSpace == this.nameSpace) this - else NamedType(prefix, designator.withNameSpace(nameSpace)) + 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 + + /** 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 + 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 (prefix eq this.prefix) this + else 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 => @@ -1945,22 +1959,26 @@ 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 ""}" - */ + /** A reference to an implicit definition. This can be either a TermRef or a + * Implicits.RenamedImplicitRef. + */ + trait ImplicitRef { + def implicitName(implicit ctx: Context): TermName + def underlyingRef: TermRef } - abstract case class TermRef(override val prefix: Type, designator: TermDesignator) extends NamedType with SingletonType { + 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 @@ -1969,63 +1987,36 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded - private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef(prefix, name, sd) - def alternatives(implicit ctx: Context): List[TermRef] = - denot.alternatives map rewrap + denot.alternatives.map(withDenot(_)) def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[TermRef] = - 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 - val ownSym = symbol - val newd = asMemberOf(prefix, allowPrivate = ownSym.is(Private)) - candidate.withDenot(newd.suchThat(_.signature == ownSym.signature)) - } - else candidate + denot.altsWith(p).map(withDenot(_)) - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = designator match { - case designator: TermSymbol @unchecked => - TermRef(prefix, designator) - case _ => - // 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 - fixDenot(TermRef(prefix, designator1), prefix) - } + def implicitName(implicit ctx: Context): TermName = name + def underlyingRef = this } - abstract case class TypeRef(override val prefix: Type, designator: TypeDesignator) extends NamedType { + abstract case class TypeRef(override val prefix: Type, + private var myDesignator: Designator) + extends NamedType { type ThisType = TypeRef type ThisName = TypeName - override def underlying(implicit ctx: Context): Type = info + override def designator = myDesignator + override protected def designator_=(d: Designator) = myDesignator = d - def withPrefix(prefix: Type)(implicit ctx: Context): NamedType = - TypeRef(prefix, designator) + override def underlying(implicit ctx: Context): Type = info } - 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 } @@ -2034,75 +2025,42 @@ 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(prefix, designator.asType) - else TermRef(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(prefix, designator.asTermName, denot) - else TypeRef(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) + if (designator.isTermName) TermRef.apply(prefix, designator.asTermName, denot) + else TypeRef.apply(prefix, designator.asTypeName, denot) } 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. - */ - def apply(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] + /** 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 = { - 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 withSym(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) - - def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - withSym(prefix, sym, sym.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) } object TypeRef { - /** Create type ref with given prefix and name */ - def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = + /** 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 */ - 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)) - } 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 + /** 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 withSym(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) - - def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - withSym(prefix, sym, sym.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) } // --- Other SingletonTypes: ThisType/SuperType/ConstantType --------------------------- @@ -3445,18 +3403,12 @@ 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) symbolicTypeRef // ??? 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 } - def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef.withSym(prefix, cls) - // cached because baseType needs parents private[this] var parentsCache: List[Type] = null @@ -3528,10 +3480,13 @@ 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). - contains(tp.symbolicTypeRef) // ??? not clear - 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 = @@ -3797,7 +3752,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/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index da5ff8085638..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 @@ -56,10 +56,9 @@ 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 (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 e13311ddeb4d..a210cb9a4671 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -319,7 +319,7 @@ 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) + TypeRef(processInner(tp.prefix.widen), tp.symbol.asType) case _ => tp } 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/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 0f727cf8f101..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._ @@ -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) @@ -73,10 +78,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 => @@ -148,6 +151,25 @@ class TreePickler(pickler: TastyPickler) { writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect) pickleSymRef(sym) } + def pickleExternalRef(sym: Symbol) = { + def pickleCore() = { + pickleNameAndSig(sym.name, tpe.signature) + pickleType(tpe.prefix) + } + 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() + pickleType(sym.owner.typeRef) + } + } + else { + writeByte(if (tpe.isType) TYPEREF else TERMREF) + pickleCore() + } + } if (sym.is(Flags.Package)) { writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg) pickleName(sym.fullName) @@ -171,13 +193,8 @@ 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) } case tpe: ThisType => if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) { @@ -327,9 +344,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) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 09677d9490ec..19dc90b31d43 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -222,15 +222,20 @@ 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)) + 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] - TypeRef(prefix, name.withNameSpace(space)) + val space = readType() + TypeRef(prefix, name, space.decl(name)) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -287,11 +292,17 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case TERMREFpkg => readPackageRef().termRef case TYPEREF => - val name = readName().toTypeName + val name = readName().toTypeName TypeRef(readType(), name) case TERMREF => - val name = readName() - TermRef(readType(), name) + val sname = readName() + val prefix = readType() + 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 => @@ -341,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 @@ -723,8 +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, 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 c08da6aa2559..a2542cbaefee 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 (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 case _ => } - val tycon = - if (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) { - 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/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..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._ @@ -110,4 +111,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..505f68d28007 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 = { @@ -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)) 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 = "" diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 3de005fac34b..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.initialDenot.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/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index ecb40b52a910..670fb2f47ac9 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -85,8 +85,11 @@ class Erasure extends Phase with DenotTransformer { ref.copySymDenotation(symbol = newSymbol, owner = newOwner, initFlags = newFlags, info = newInfo) } } - case ref => - ref.derivedSingleDenotation(ref.symbol, transformInfo(ref.symbol, ref.info)) + 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)) } val eraser = new Erasure.Typer 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") diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 901b1a316211..52ef9b1d9a0a 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) - // 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)) typr.println(i"adding param forwarder $superAcc") DefDef(sym, superAcc.ensureConforms(sym.info.widen)) } @@ -90,17 +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.tpe match { - case tpe: TermRef - if 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 - } } 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 diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 8ad6cee9e2af..0bec80c49cb9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -79,17 +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.tpe match { - case tpe: TermRef if tpe.signature.isUnderDefined => - 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 - } - class PostTyperTransformer extends Transformer { private[this] var inJavaAnnot: Boolean = false @@ -175,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) { @@ -183,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/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) && 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/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 799932f97bc8..61dfd30866d7 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) @@ -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/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/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index e922a1a55c14..259fb1048cf4 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 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(ref: TermRef, level: Int) + case class Candidate(implicitRef: ImplicitRef, level: Int) { + def ref: TermRef = implicitRef.underlyingRef + } /** 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[ImplicitRef] /** 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.underlyingRef)(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[ImplicitRef] = { 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[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 @@ -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)) } } @@ -341,8 +350,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, @@ -432,7 +447,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] } @@ -646,12 +661,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 => @@ -806,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.implicitRef.implicitName) withPos pos.toSynthetic, funProto)( nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState()) def refSameAs(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { @@ -1020,7 +1041,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 } } } @@ -1114,7 +1143,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) diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 8b06148a7723..596a6092bd5d 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.RenamedImplicitRef 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[ImplicitRef] = { 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 RenamedImplicitRef(ref, renamed) + } } /** The root import symbol hidden by this symbol, or NoSymbol if no such symbol is hidden. diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 23f1871c83e1..9db27eddc9f7 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, "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 { @@ -1195,12 +1198,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.uncheckedSetSym(null) + tref.recomputeDenot() 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 13f2dbb1c316..fe0fec988c75 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -188,7 +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(tpe.withNameSpace(noNameSpace).withDenot(d2), false) + test(NamedType(pre, name, d2), false) else if (pre.derivesFrom(defn.DynamicClass)) { TryDynamicCallType } else { @@ -208,8 +208,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 } @@ -413,6 +412,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) } 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) } } 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() 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) + } +} 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/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 +} 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)) +} + 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 }