diff options
Diffstat (limited to 'src/reflect/scala/reflect/internal/Types.scala')
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 413 |
1 files changed, 223 insertions, 190 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 9697e16da7..de82a6a0b2 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -7,7 +7,7 @@ package scala package reflect package internal -import scala.collection.{ mutable, immutable, generic } +import scala.collection.{ mutable, immutable } import scala.ref.WeakReference import mutable.ListBuffer import Flags._ @@ -462,7 +462,7 @@ trait Types * the empty list for all other types */ def boundSyms: immutable.Set[Symbol] = emptySymbolSet - /** Replace formal type parameter symbols with actual type arguments. + /** Replace formal type parameter symbols with actual type arguments. ErrorType on arity mismatch. * * Amounts to substitution except for higher-kinded types. (See overridden method in TypeRef) -- @M */ @@ -589,7 +589,12 @@ trait Types def nonPrivateMembersAdmitting(admit: Long): Scope = membersBasedOnFlags(BridgeAndPrivateFlags & ~admit, 0) /** A list of all implicit symbols of this type (defined or inherited) */ - def implicitMembers: Scope = membersBasedOnFlags(BridgeFlags, IMPLICIT) + def implicitMembers: Scope = { + typeSymbolDirect match { + case sym: ModuleClassSymbol => sym.implicitMembers + case _ => membersBasedOnFlags(BridgeFlags, IMPLICIT) + } + } /** A list of all deferred symbols of this type (defined or inherited) */ def deferredMembers: Scope = membersBasedOnFlags(BridgeFlags, DEFERRED) @@ -606,6 +611,8 @@ trait Types def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) + def packageObject: Symbol = member(nme.PACKAGE) + /** The non-private member with given name, admitting members with given flags `admit`. * "Admitting" refers to the fact that members with a PRIVATE, BRIDGE, or VBRIDGE * flag are usually excluded from findMember results, but supplying any of those flags @@ -659,7 +666,7 @@ trait Types ) if (trivial) this else { - val m = newAsSeenFromMap(pre.normalize, clazz) + val m = new AsSeenFromMap(pre.normalize, clazz) val tp = m(this) val tp1 = existentialAbstraction(m.capturedParams, tp) @@ -1189,7 +1196,6 @@ trait Types object ThisType extends ThisTypeExtractor { def apply(sym: Symbol): Type = ( if (!phase.erasedTypes) unique(new UniqueThisType(sym)) - else if (sym.isImplClass) sym.typeOfThis else sym.tpe_* ) } @@ -1207,6 +1213,10 @@ trait Types private[reflect] var underlyingCache: Type = NoType private[reflect] var underlyingPeriod = NoPeriod + private[Types] def invalidateSingleTypeCaches(): Unit = { + underlyingCache = NoType + underlyingPeriod = NoPeriod + } override def underlying: Type = { val cache = underlyingCache if (underlyingPeriod == currentPeriod && cache != null) cache @@ -1347,6 +1357,12 @@ trait Types private[reflect] var baseTypeSeqPeriod = NoPeriod private[reflect] var baseClassesCache: List[Symbol] = _ private[reflect] var baseClassesPeriod = NoPeriod + private[Types] def invalidatedCompoundTypeCaches() { + baseTypeSeqCache = null + baseTypeSeqPeriod = NoPeriod + baseClassesCache = null + baseClassesPeriod = NoPeriod + } override def baseTypeSeq: BaseTypeSeq = { val cached = baseTypeSeqCache @@ -1600,7 +1616,14 @@ trait Types private var normalized: Type = _ private def normalizeImpl = { // TODO see comments around def intersectionType and def merge - def flatten(tps: List[Type]): List[Type] = tps flatMap { case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) case tp => List(tp) } + // SI-8575 The dealias is needed here to keep subtyping transitive, example in run/t8575b.scala + def flatten(tps: List[Type]): List[Type] = { + def dealiasRefinement(tp: Type) = if (tp.dealias.isInstanceOf[RefinedType]) tp.dealias else tp + tps map dealiasRefinement flatMap { + case RefinedType(parents, ds) if ds.isEmpty => flatten(parents) + case tp => List(tp) + } + } val flattened = flatten(parents).distinct if (decls.isEmpty && hasLength(flattened, 1)) { flattened.head @@ -1843,53 +1866,13 @@ trait Types override def isHigherKinded = false override def typeParams = Nil - override def transform(tp: Type): Type = { - // This situation arises when a typevar is encountered for which - // too little information is known to determine its kind, and - // it later turns out not to have kind *. See SI-4070. Only - // logging it for now. - val tparams = sym.typeParams - if (tparams.size != args.size) - devWarning(s"$this.transform($tp), but tparams.isEmpty and args=$args") - def asSeenFromInstantiated(tp: Type) = - asSeenFromOwner(tp).instantiateTypeParams(tparams, args) - // If we're called with a poly type, and we were to run the `asSeenFrom`, over the entire - // type, we can end up with new symbols for the type parameters (clones from TypeMap). - // The subsequent substitution of type arguments would fail. This problem showed up during - // the fix for SI-8046, however the solution taken there wasn't quite right, and led to - // SI-8170. - // - // Now, we detect the PolyType before both the ASF *and* the substitution, and just operate - // on the result type. - // - // TODO: Revisit this and explore the questions raised: - // - // AM: I like this better than the old code, but is there any way the tparams would need the ASF treatment as well? - // JZ: I think its largely irrelevant, as they are no longer referred to in the result type. - // In fact, you can get away with returning a type of kind * here and the sky doesn't fall: - // `case PolyType(`tparams`, result) => asSeenFromInstantiated(result)` - // But I thought it was better to retain the kind. - // AM: I've been experimenting with apply-type-args-then-ASF, but running into cycles. - // In general, it seems iffy the tparams can never occur in the result - // then we might as well represent the type as a no-arg typeref. - // AM: I've also been trying to track down uses of transform (pretty generic name for something that - // does not seem that widely applicable). - // It's kind of a helper for computing baseType (since it tries to propagate our type args to some - // other type, which has to be related to this type for that to make sense). - // - tp match { - case PolyType(`tparams`, result) => PolyType(tparams, asSeenFromInstantiated(result)) - case _ => asSeenFromInstantiated(tp) - } - } - // note: does not go through typeRef. There's no need to because // neither `pre` nor `sym` changes. And there's a performance // advantage to call TypeRef directly. override def typeConstructor = TypeRef(pre, sym, Nil) } - class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef { + class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) { require(sym.isModuleClass, sym) private[this] var narrowedCache: Type = _ override def narrow = { @@ -1898,6 +1881,10 @@ trait Types narrowedCache } + override private[Types] def invalidateTypeRefCaches(): Unit = { + super.invalidateTypeRefCaches() + narrowedCache = null + } override protected def finishPrefix(rest: String) = objectPrefix + rest override def directObjectString = super.safeToString override def toLongString = toString @@ -1908,12 +1895,12 @@ trait Types require(sym.isPackageClass, sym) override protected def finishPrefix(rest: String) = packagePrefix + rest } - class RefinementTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef { + class RefinementTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) { require(sym.isRefinementClass, sym) // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers override protected def normalizeImpl: Type = sym.info.normalize - override protected def finishPrefix(rest: String) = "" + thisInfo + override protected def finishPrefix(rest: String) = "" + sym.info } class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) { @@ -1924,7 +1911,6 @@ trait Types // represented as existential types. override def isHigherKinded = (typeParams ne Nil) override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams - private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = if (isHigherKinded) { @@ -1937,17 +1923,6 @@ trait Types else super.instantiateTypeParams(formals, actuals) - override def transform(tp: Type): Type = { - val res = asSeenFromOwner(tp) - if (isHigherKinded && !isRaw) - res.instantiateTypeParams(typeParams, dummyArgs) - else - res - } - - override def transformInfo(tp: Type): Type = - appliedType(asSeenFromOwner(tp), dummyArgs) - override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) else super.narrow @@ -1959,65 +1934,75 @@ trait Types if (isHigherKinded) etaExpand else super.normalizeImpl } - trait ClassTypeRef extends TypeRef { - // !!! There are scaladoc-created symbols arriving which violate this require. - // require(sym.isClass, sym) - - override def baseType(clazz: Symbol): Type = - if (sym == clazz) this - else transform(sym.info.baseType(clazz)) - } - trait NonClassTypeRef extends TypeRef { require(sym.isNonClassType, sym) - /* Syncnote: These are pure caches for performance; no problem to evaluate these - * several times. Hence, no need to protected with synchronized in a multi-threaded - * usage scenario. - */ + /** Syncnote: These are pure caches for performance; no problem to evaluate these + * several times. Hence, no need to protected with synchronized in a multi-threaded + * usage scenario. + */ private var relativeInfoCache: Type = _ - private var relativeInfoPeriod: Period = NoPeriod + private var relativeInfoCacheValidForPeriod: Period = NoPeriod + private var relativeInfoCacheValidForSymInfo: Type = _ - private[Types] def relativeInfo = /*trace(s"relativeInfo(${safeToString}})")*/{ - if (relativeInfoPeriod != currentPeriod) { - val memberInfo = pre.memberInfo(sym) - relativeInfoCache = transformInfo(memberInfo) - relativeInfoPeriod = currentPeriod + override private[Types] def invalidateTypeRefCaches(): Unit = { + super.invalidateTypeRefCaches() + relativeInfoCache = NoType + relativeInfoCacheValidForPeriod = NoPeriod + relativeInfoCacheValidForSymInfo = null + } + + final override protected def relativeInfo = { + val symInfo = sym.info + if ((relativeInfoCache eq null) || (relativeInfoCacheValidForSymInfo ne symInfo) || (relativeInfoCacheValidForPeriod != currentPeriod)) { + relativeInfoCache = super.relativeInfo + + if (this.isInstanceOf[AbstractTypeRef]) validateRelativeInfo() + + relativeInfoCacheValidForSymInfo = symInfo + relativeInfoCacheValidForPeriod = currentPeriod } relativeInfoCache } - override def baseType(clazz: Symbol): Type = - if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz) + private def validateRelativeInfo(): Unit = relativeInfoCache match { + // If a subtyping cycle is not detected here, we'll likely enter an infinite + // loop before a sensible error can be issued. SI-5093 is one example. + case x: SubType if x.supertype eq this => + relativeInfoCache = null + throw new RecoverableCyclicReference(sym) + case _ => + } } - protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try { - basetypeRecursions += 1 - if (basetypeRecursions < LogPendingBaseTypesThreshold) - tpe.relativeInfo.baseType(clazz) - else if (pendingBaseTypes contains tpe) - if (clazz == AnyClass) clazz.tpe else NoType - else - try { - pendingBaseTypes += tpe - tpe.relativeInfo.baseType(clazz) - } finally { - pendingBaseTypes -= tpe - } - } finally { - basetypeRecursions -= 1 - } trait AliasTypeRef extends NonClassTypeRef { require(sym.isAliasType, sym) override def dealias = if (typeParamsMatchArgs) betaReduce.dealias else super.dealias override def narrow = normalize.narrow - override def thisInfo = normalize override def prefix = if (this ne normalize) normalize.prefix else pre override def termSymbol = if (this ne normalize) normalize.termSymbol else super.termSymbol override def typeSymbol = if (this ne normalize) normalize.typeSymbol else sym + override protected[Types] def parentsImpl: List[Type] = normalize.parents map relativize + + // `baseClasses` is sensitive to type args when referencing type members + // consider `type foo[x] = x`, `typeOf[foo[String]].baseClasses` should be the same as `typeOf[String].baseClasses`, + // which would be lost by looking at `sym.info` without propagating args + // since classes cannot be overridden, the prefix can be ignored + // (in fact, taking the prefix into account by replacing `normalize` + // with `relativeInfo` breaks pos/t8177g.scala, which is probably a bug, but a tricky one... + override def baseClasses = normalize.baseClasses + + // similar reasoning holds here as for baseClasses + // as another example, consider the type alias `Foo` in `class O { o => type Foo = X { val bla: o.Bar }; type Bar }` + // o1.Foo and o2.Foo have different decls `val bla: o1.Bar` versus `val bla: o2.Bar` + // In principle, you should only call `sym.info.decls` when you know `sym.isClass`, + // and you should `relativize` the infos of the resulting members. + // The latter is certainly violated in multiple spots in the codebase (the members are usually transformed correctly, though). + override def decls: Scope = normalize.decls + // beta-reduce, but don't do partial application -- cycles have been checked in typeRef override protected def normalizeImpl = if (typeParamsMatchArgs) betaReduce.normalize @@ -2040,7 +2025,7 @@ trait Types // // this crashes pos/depmet_implicit_tpbetareduce.scala // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) - override def betaReduce = transform(sym.info.resultType) + override def betaReduce = relativize(sym.info.resultType) /** SI-3731, SI-8177: when prefix is changed to `newPre`, maintain consistency of prefix and sym * (where the symbol refers to a declaration "embedded" in the prefix). @@ -2090,27 +2075,13 @@ trait Types trait AbstractTypeRef extends NonClassTypeRef { require(sym.isAbstractType, sym) - /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment - */ - private var symInfoCache: Type = _ - private var thisInfoCache: Type = _ + override def baseClasses = relativeInfo.baseClasses + override def decls = relativeInfo.decls + override def bounds = relativeInfo.bounds + + override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = bounds.hi.baseTypeSeq prepend this + override protected[Types] def parentsImpl: List[Type] = relativeInfo.parents - override def thisInfo = { - val symInfo = sym.info - if (thisInfoCache == null || (symInfo ne symInfoCache)) { - symInfoCache = symInfo - thisInfoCache = transformInfo(symInfo) match { - // If a subtyping cycle is not detected here, we'll likely enter an infinite - // loop before a sensible error can be issued. SI-5093 is one example. - case x: SubType if x.supertype eq this => - throw new RecoverableCyclicReference(sym) - case tp => tp - } - } - thisInfoCache - } - override def bounds = thisInfo.bounds - override protected[Types] def baseTypeSeqImpl: BaseTypeSeq = transform(bounds.hi).baseTypeSeq prepend this override def kind = "AbstractTypeRef" } @@ -2128,9 +2099,12 @@ trait Types trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args)) toBoolean(trivial) } - private[scala] def invalidateCaches(): Unit = { + private[Types] def invalidateTypeRefCaches(): Unit = { + parentsCache = null parentsPeriod = NoPeriod + baseTypeSeqCache = null baseTypeSeqPeriod = NoPeriod + normalized = null } private[reflect] var parentsCache: List[Type] = _ private[reflect] var parentsPeriod = NoPeriod @@ -2151,11 +2125,91 @@ trait Types finalizeHash(h, 2) } + // interpret symbol's info in terms of the type's prefix and type args + protected def relativeInfo: Type = appliedType(sym.info.asSeenFrom(pre, sym.owner), argsOrDummies) + // @M: propagate actual type params (args) to `tp`, by replacing // formal type parameters with actual ones. If tp is higher kinded, // the "actual" type arguments are types that simply reference the // corresponding type parameters (unbound type variables) - def transform(tp: Type): Type + // + // NOTE: for performance, as well as correctness, we do not attempt + // to reframe trivial types in terms of our prefix and args. + // asSeenFrom, by construction, is the identity for trivial types, + // and substitution cannot change them either (abstract types are non-trivial, specifically because they may need to be replaced) + // For correctness, the result for `tp == NoType` must be `NoType`, + // if we don't shield against this, and apply instantiateTypeParams to it, + // this would result in an ErrorType, which behaves differently during subtyping + // (and thus on recursion, subtyping would go from false -- since a NoType is involved -- + // to true, as ErrorType is always a sub/super type....) + final def relativize(tp: Type): Type = + if (tp.isTrivial) tp + else if (args.isEmpty && (phase.erasedTypes || !isHigherKinded || isRawIfWithoutArgs(sym))) tp.asSeenFrom(pre, sym.owner) + else { + // The type params and type args should always match in length, + // though a mismatch can arise when a typevar is encountered for which + // too little information is known to determine its kind, and + // it later turns out not to have kind *. See SI-4070. + val formals = sym.typeParams + + // If we're called with a poly type, and we were to run the `asSeenFrom`, over the entire + // type, we can end up with new symbols for the type parameters (clones from TypeMap). + // The subsequent substitution of type arguments would fail. This problem showed up during + // the fix for SI-8046, however the solution taken there wasn't quite right, and led to + // SI-8170. + // + // Now, we detect the PolyType before both the ASF *and* the substitution, and just operate + // on the result type. + // + // TODO: Revisit this and explore the questions raised: + // + // AM: I like this better than the old code, but is there any way the tparams would need the ASF treatment as well? + // JZ: I think its largely irrelevant, as they are no longer referred to in the result type. + // In fact, you can get away with returning a type of kind * here and the sky doesn't fall: + // `case PolyType(`tparams`, result) => asSeenFromInstantiated(result)` + // But I thought it was better to retain the kind. + // AM: I've been experimenting with apply-type-args-then-ASF, but running into cycles. + // In general, it seems iffy the tparams can never occur in the result + // then we might as well represent the type as a no-arg typeref. + // AM: I've also been trying to track down uses of transform (pretty generic name for something that + // does not seem that widely applicable). + // It's kind of a helper for computing baseType (since it tries to propagate our type args to some + // other type, which has to be related to this type for that to make sense). + // + def seenFromOwnerInstantiated(tp: Type): Type = + tp.asSeenFrom(pre, sym.owner).instantiateTypeParams(formals, argsOrDummies) + + tp match { + case PolyType(`formals`, result) => PolyType(formals, seenFromOwnerInstantiated(result)) + case _ => seenFromOwnerInstantiated(tp) + } + } + + private def argsOrDummies = if (args.isEmpty) dummyArgs else args + + final override def baseType(clazz: Symbol): Type = + if (clazz eq sym) this + // NOTE: this first goes to requested base type, *then* does asSeenFrom prefix & instantiates args + else if (sym.isClass) relativize(sym.info.baseType(clazz)) + else baseTypeOfNonClassTypeRef(clazz) + + // two differences with class type basetype: + // (1) first relativize the type, then go to the requested base type + // (2) cache for cycle robustness + private def baseTypeOfNonClassTypeRef(clazz: Symbol) = + try { + basetypeRecursions += 1 + if (basetypeRecursions >= LogPendingBaseTypesThreshold) baseTypeOfNonClassTypeRefLogged(clazz) + else relativeInfo.baseType(clazz) + } finally basetypeRecursions -= 1 + + private def baseTypeOfNonClassTypeRefLogged(clazz: Symbol) = + if (pendingBaseTypes add this) try relativeInfo.baseType(clazz) finally { pendingBaseTypes remove this } + // TODO: is this optimization for AnyClass worth it? (or is it playing last-ditch cycle defense?) + // NOTE: for correctness, it only applies for non-class types + // (e.g., a package class should not get AnyTpe as its supertype, ever) + else if (clazz eq AnyClass) AnyTpe + else NoType // eta-expand, subtyping relies on eta-expansion of higher-kinded types protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalize @@ -2188,21 +2242,16 @@ trait Types // (they are allowed to be rebound more liberally) def coevolveSym(pre1: Type): Symbol = sym - //@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs) - def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), args) - - def thisInfo = sym.info def initializedTypeParams = sym.info.typeParams def typeParamsMatchArgs = sameLength(initializedTypeParams, args) - def asSeenFromOwner(tp: Type) = tp.asSeenFrom(pre, sym.owner) - override def baseClasses = thisInfo.baseClasses + override def baseTypeSeqDepth = baseTypeSeq.maxDepth override def prefix = pre override def termSymbol = super.termSymbol override def termSymbolDirect = super.termSymbol override def typeArgs = args - override def typeOfThis = transform(sym.typeOfThis) + override def typeOfThis = relativize(sym.typeOfThis) override def typeSymbol = sym override def typeSymbolDirect = sym @@ -2215,22 +2264,26 @@ trait Types } } - override def decls: Scope = { - sym.info match { - case TypeRef(_, sym1, _) => - assert(sym1 != sym, this) // @MAT was != typeSymbol - case _ => - } - thisInfo.decls - } + protected[Types] def parentsImpl: List[Type] = sym.info.parents map relativize + + // Since type parameters cannot occur in super types, no need to relativize before looking at base *classes*. + // Similarly, our prefix can occur in super class types, but it cannot influence which classes those types resolve to. + // For example, `class Outer { outer => class Inner extends outer.Foo; class Foo }` + // `outer`'s value has no impact on which `Foo` is selected, since classes cannot be overridden. + // besides being faster, we can't use relativeInfo because it causes cycles + override def baseClasses = sym.info.baseClasses + + // in principle, we should use `relativeInfo.decls`, but I believe all uses of `decls` will correctly `relativize` the individual members + override def decls: Scope = sym.info.decls + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = if (sym.info.baseTypeSeq exists (_.typeSymbolDirect.isAbstractType)) // SI-8046 base type sequence might have more elements in a subclass, we can't map it element wise. - transform(sym.info).baseTypeSeq + relativize(sym.info).baseTypeSeq else // Optimization: no abstract types, we can compute the BTS of this TypeRef as an element-wise map // of the BTS of the referenced symbol. - sym.info.baseTypeSeq map transform + sym.info.baseTypeSeq map relativize override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache @@ -2261,9 +2314,10 @@ trait Types ) protected def finishPrefix(rest: String) = ( if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes) - parentsString(thisInfo.parents) + refinementString + parentsString(sym.info.parents) + refinementString else rest - ) + ) + private def noArgsString = finishPrefix(preString + sym.nameString) private def tupleTypeString: String = args match { case Nil => noArgsString @@ -2325,10 +2379,10 @@ trait Types // No longer defined as anonymous classes in `object TypeRef` to avoid an unnecessary outer pointer. private final class AliasArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AliasTypeRef private final class AbstractArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AbstractTypeRef - private final class ClassArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with ClassTypeRef + private final class ClassArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) private final class AliasNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AliasTypeRef private final class AbstractNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AbstractTypeRef - private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with ClassTypeRef + private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) object TypeRef extends TypeRefExtractor { def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({ @@ -2353,7 +2407,7 @@ trait Types if (period != currentPeriod) { tpe.parentsPeriod = currentPeriod if (!isValidForBaseClasses(period)) { - tpe.parentsCache = tpe.thisInfo.parents map tpe.transform + tpe.parentsCache = tpe.parentsImpl } else if (tpe.parentsCache == null) { // seems this can happen if things are corrupted enough, see #2641 tpe.parentsCache = List(AnyTpe) } @@ -2408,7 +2462,6 @@ trait Types def isImplicit = (params ne Nil) && params.head.isImplicit def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized? - //assert(paramTypes forall (pt => !pt.typeSymbol.isImplClass))//DEBUG override def paramSectionCount: Int = resultType.paramSectionCount + 1 override def paramss: List[List[Symbol]] = params :: resultType.paramss @@ -2458,6 +2511,8 @@ trait Types override def isJava = true } + // TODO: rename so it's more appropriate for the type that is for a method without argument lists + // ("nullary" erroneously implies it has an argument list with zero arguments, it actually has zero argument lists) case class NullaryMethodType(override val resultType: Type) extends Type with NullaryMethodTypeApi { override def isTrivial = resultType.isTrivial && (resultType eq resultType.withoutAnnotations) override def prefix: Type = resultType.prefix @@ -3877,6 +3932,8 @@ trait Types et.withTypeVars(isConsistent(_, tp2)) case (_, et: ExistentialType) => et.withTypeVars(isConsistent(tp1, _)) + case (_, _) => + throw new MatchError((tp1, tp2)) } def check(tp1: Type, tp2: Type) = ( @@ -3889,54 +3946,15 @@ trait Types check(tp1, tp2) && check(tp2, tp1) } - /** Does a pattern of type `patType` need an outer test when executed against - * selector type `selType` in context defined by `currentOwner`? - */ - def needsOuterTest(patType: Type, selType: Type, currentOwner: Symbol) = { - def createDummyClone(pre: Type): Type = { - val dummy = currentOwner.enclClass.newValue(nme.ANYname).setInfo(pre.widen) - singleType(ThisType(currentOwner.enclClass), dummy) - } - def maybeCreateDummyClone(pre: Type, sym: Symbol): Type = pre match { - case SingleType(pre1, sym1) => - if (sym1.isModule && sym1.isStatic) { - NoType - } else if (sym1.isModule && sym.owner == sym1.moduleClass) { - val pre2 = maybeCreateDummyClone(pre1, sym1) - if (pre2 eq NoType) pre2 - else singleType(pre2, sym1) - } else { - createDummyClone(pre) - } - case ThisType(clazz) => - if (clazz.isModuleClass) - maybeCreateDummyClone(clazz.typeOfThis, sym) - else if (sym.owner == clazz && (sym.hasFlag(PRIVATE) || sym.privateWithin == clazz)) - NoType - else - createDummyClone(pre) - case _ => - NoType - } - // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` - // generates an outer test based on `patType.prefix` with automatically dealises. - patType.dealias match { - case TypeRef(pre, sym, args) => - val pre1 = maybeCreateDummyClone(pre, sym) - (pre1 ne NoType) && isPopulated(copyTypeRef(patType, pre1, sym, args), selType) - case _ => - false - } - } - - def normalizePlus(tp: Type) = ( + def normalizePlus(tp: Type): Type = { if (isRawType(tp)) rawToExistential(tp) else tp.normalize match { - // Unify the two representations of module classes - case st @ SingleType(_, sym) if sym.isModule => st.underlying.normalize - case _ => tp.normalize + // Unify the representations of module classes + case st@SingleType(_, sym) if sym.isModule => st.underlying.normalize + case st@ThisType(sym) if sym.isModuleClass => normalizePlus(st.underlying) + case _ => tp.normalize } - ) + } /* todo: change to: @@ -4555,6 +4573,21 @@ trait Types if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyTpe else tp + def invalidateTreeTpeCaches(tree: Tree, updatedSyms: List[Symbol]) = if (updatedSyms.nonEmpty) + for (t <- tree if t.tpe != null) + for (tp <- t.tpe) { + invalidateCaches(tp, updatedSyms) + } + + def invalidateCaches(t: Type, updatedSyms: List[Symbol]) = + t match { + case st: SingleType if updatedSyms.contains(st.sym) => st.invalidateSingleTypeCaches() + case tr: TypeRef if updatedSyms.contains(tr.sym) => tr.invalidateTypeRefCaches() + case ct: CompoundType if ct.baseClasses.exists(updatedSyms.contains) => ct.invalidatedCompoundTypeCaches() + case _ => + } + + val shorthands = Set( "scala.collection.immutable.List", "scala.collection.immutable.Nil", |