From 5f8820c2eac46b21539ad1de17c97eb75d3ab105 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Jul 2017 13:44:35 +0200 Subject: [PATCH 1/3] Introduce AppliedType AppliedType will be used for all type applications, higher-kinded or not. That is, eventually, it will replace HKApply and also the encodings of type applications as refined types. This commit introduces AppliedType and adapts baseType computations to take it into account. AppliedType is not yet constructed anywhere, however. --- .../tools/dotc/core/SymDenotations.scala | 64 +++++------ .../tools/dotc/core/TypeApplications.scala | 14 ++- .../dotty/tools/dotc/core/TypeComparer.scala | 8 +- .../src/dotty/tools/dotc/core/TypeOps.scala | 6 +- .../src/dotty/tools/dotc/core/Types.scala | 107 +++++++++++++++++- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 6 +- .../tools/dotc/printing/RefinedPrinter.scala | 4 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 10 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- .../tools/dottydoc/model/factories.scala | 2 +- 14 files changed, 168 insertions(+), 65 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index bfaa12729090..6c3204eaacfb 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -699,7 +699,7 @@ object SymDenotations { | is not a subclass of ${owner.showLocated} where target is defined""") else if ( !( isType // allow accesses to types from arbitrary subclasses fixes #4737 - || pre.baseTypeRef(cls).exists // ??? why not use derivesFrom ??? + || pre.derivesFrom(cls) || isConstructor || (owner is ModuleClass) // don't perform this check for static members )) @@ -1266,10 +1266,10 @@ object SymDenotations { private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null private[this] var myMemberCachePeriod: Period = Nowhere - /** A cache from types T to baseTypeRef(T, C) */ - type BaseTypeRefMap = java.util.HashMap[CachedType, Type] - private[this] var myBaseTypeRefCache: BaseTypeRefMap = null - private[this] var myBaseTypeRefCachePeriod: Period = Nowhere + /** A cache from types T to baseType(T, C) */ + type BaseTypeMap = java.util.HashMap[CachedType, Type] + private[this] var myBaseTypeCache: BaseTypeMap = null + private[this] var myBaseTypeCachePeriod: Period = Nowhere private var baseDataCache: BaseData = BaseData.None private var memberNamesCache: MemberNames = MemberNames.None @@ -1282,14 +1282,14 @@ object SymDenotations { myMemberCache } - private def baseTypeRefCache(implicit ctx: Context): BaseTypeRefMap = { - if (myBaseTypeRefCachePeriod != ctx.period && - (myBaseTypeRefCachePeriod.runId != ctx.runId || - ctx.phases(myBaseTypeRefCachePeriod.phaseId).sameParentsStartId != ctx.phase.sameParentsStartId)) { - myBaseTypeRefCache = new BaseTypeRefMap - myBaseTypeRefCachePeriod = ctx.period + private def baseTypeCache(implicit ctx: Context): BaseTypeMap = { + if (myBaseTypeCachePeriod != ctx.period && + (myBaseTypeCachePeriod.runId != ctx.runId || + ctx.phases(myBaseTypeCachePeriod.phaseId).sameParentsStartId != ctx.phase.sameParentsStartId)) { + myBaseTypeCache = new BaseTypeMap + myBaseTypeCachePeriod = ctx.period } - myBaseTypeRefCache + myBaseTypeCache } private def invalidateBaseDataCache() = { @@ -1302,9 +1302,9 @@ object SymDenotations { memberNamesCache = MemberNames.None } - def invalidateBaseTypeRefCache() = { - myBaseTypeRefCache = null - myBaseTypeRefCachePeriod = Nowhere + def invalidateBaseTypeCache() = { + myBaseTypeCache = null + myBaseTypeCachePeriod = Nowhere } override def copyCaches(from: SymDenotation, phase: Phase)(implicit ctx: Context): this.type = { @@ -1313,7 +1313,7 @@ object SymDenotations { if (from.memberNamesCache.isValidAt(phase)) memberNamesCache = from.memberNamesCache if (from.baseDataCache.isValidAt(phase)) { baseDataCache = from.baseDataCache - myBaseTypeRefCache = from.baseTypeRefCache + myBaseTypeCache = from.baseTypeCache } case _ => } @@ -1581,11 +1581,11 @@ object SymDenotations { raw.filterExcluded(excluded).asSeenFrom(pre).toDenot(pre) } - /** Compute tp.baseTypeRef(this) */ - final def baseTypeRefOf(tp: Type)(implicit ctx: Context): Type = { + /** Compute tp.baseType(this) */ + final def baseTypeOf(tp: Type)(implicit ctx: Context): Type = { def foldGlb(bt: Type, ps: List[Type]): Type = ps match { - case p :: ps1 => foldGlb(bt & baseTypeRefOf(p), ps1) + case p :: ps1 => foldGlb(bt & baseTypeOf(p), ps1) case _ => bt } @@ -1597,7 +1597,7 @@ object SymDenotations { * and this changes subtyping relations. As a shortcut, we do not * cache ErasedValueType at all. */ - def isCachable(tp: Type, btrCache: BaseTypeRefMap): Boolean = { + def isCachable(tp: Type, btrCache: BaseTypeMap): Boolean = { def inCache(tp: Type) = btrCache.containsKey(tp) tp match { case _: TypeErasure.ErasedValueType => false @@ -1609,12 +1609,12 @@ object SymDenotations { } } - def computeBaseTypeRefOf(tp: Type): Type = { + def computeBaseTypeOf(tp: Type): Type = { Stats.record("computeBaseTypeOf") - if (symbol.isStatic && tp.derivesFrom(symbol)) + if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty) symbol.typeRef else tp match { - case tp: TypeRef => + case tp: RefType => val subcls = tp.symbol if (subcls eq symbol) tp @@ -1623,14 +1623,14 @@ object SymDenotations { if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parents) else NoType case _ => - baseTypeRefOf(tp.superType) + baseTypeOf(tp.superType) } case tp: TypeProxy => - baseTypeRefOf(tp.superType) + baseTypeOf(tp.superType) case AndType(tp1, tp2) => - baseTypeRefOf(tp1) & baseTypeRefOf(tp2) + baseTypeOf(tp1) & baseTypeOf(tp2) case OrType(tp1, tp2) => - baseTypeRefOf(tp1) | baseTypeRefOf(tp2) + baseTypeOf(tp1) | baseTypeOf(tp2) case JavaArrayType(_) if symbol == defn.ObjectClass => this.typeRef case _ => @@ -1638,16 +1638,16 @@ object SymDenotations { } } - /*>|>*/ ctx.debugTraceIndented(s"$tp.baseTypeRef($this)") /*<|<*/ { + /*>|>*/ ctx.debugTraceIndented(s"$tp.baseType($this)") /*<|<*/ { tp match { case tp: CachedType => - val btrCache = baseTypeRefCache + val btrCache = baseTypeCache try { var basetp = btrCache get tp if (basetp == null) { btrCache.put(tp, NoPrefix) - basetp = computeBaseTypeRefOf(tp) - if (isCachable(tp, baseTypeRefCache)) btrCache.put(tp, basetp) + basetp = computeBaseTypeOf(tp) + if (isCachable(tp, baseTypeCache)) btrCache.put(tp, basetp) else btrCache.remove(tp) } else if (basetp == NoPrefix) throw CyclicReference(this) @@ -1659,7 +1659,7 @@ object SymDenotations { throw ex } case _ => - computeBaseTypeRefOf(tp) + computeBaseTypeOf(tp) } } } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index fb2300ff1829..c12eaed6a0b0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -76,7 +76,7 @@ object TypeApplications { } def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match { - case tp @ HKTypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn) + case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn) case _ => None } } @@ -87,7 +87,7 @@ object TypeApplications { * * where v_i, p_i are the variances and names of the type parameters of T. */ - object AppliedType { + object AnyAppliedType { def apply(tp: Type, args: List[Type])(implicit ctx: Context): Type = tp.appliedTo(args) def unapply(tp: Type)(implicit ctx: Context): Option[(Type, List[Type])] = tp match { @@ -111,6 +111,8 @@ object TypeApplications { None } collectArgs(tycon.typeParams, refinements, new mutable.ListBuffer[Type]) + case AppliedType(tycon, args) => + Some((tycon, args)) case HKApply(tycon, args) => Some((tycon, args)) case _ => @@ -408,7 +410,7 @@ class TypeApplications(val self: Type) extends AnyVal { if (!args.exists(_.isInstanceOf[TypeBounds])) { val followAlias = Config.simplifyApplications && { dealiased.resType match { - case AppliedType(tyconBody, dealiasedArgs) => + case AnyAppliedType(tyconBody, dealiasedArgs) => // Reduction should not affect type inference when it's // just eta-reduction (ignoring variance annotations). // See i2201*.scala for examples where more aggressive @@ -421,7 +423,7 @@ class TypeApplications(val self: Type) extends AnyVal { else HKApply(self, args) } else dealiased.resType match { - case AppliedType(tycon, args1) if tycon.safeDealias ne tycon => + case AnyAppliedType(tycon, args1) if tycon.safeDealias ne tycon => // In this case we should always dealias since we cannot handle // higher-kinded applications to wildcard arguments. dealiased @@ -521,7 +523,7 @@ class TypeApplications(val self: Type) extends AnyVal { * Existential types in arguments are returned as TypeBounds instances. */ final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { - def default = self.baseTypeRef(base).appliedTo(baseArgInfos(base)) + def default = self.baseTypeTycon(base).appliedTo(baseArgInfos(base)) def isExpandedTypeParam(sym: Symbol) = sym.is(TypeParam) && sym.name.is(ExpandedName) self match { case tp: TypeRef => @@ -573,7 +575,7 @@ class TypeApplications(val self: Type) extends AnyVal { * Existential types in arguments are returned as TypeBounds instances. */ final def argInfos(implicit ctx: Context): List[Type] = self match { - case AppliedType(tycon, args) => args + case AnyAppliedType(tycon, args) => args case _ => Nil } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 4e911eed5bf4..80bf3be04aad 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -368,7 +368,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => val cls2 = tp2.symbol if (cls2.isClass) { - val base = tp1.baseTypeRef(cls2) + val base = tp1.baseType(cls2) if (base.exists && (base ne tp1)) return isSubType(base, tp2) if (cls2 == defn.SingletonClass && tp1.isStable) return true } @@ -713,7 +713,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match { case bc :: bcs1 => classBounds.exists(bc.derivesFrom) && - tyconOK(tp1w.baseTypeRef(bc), tp1w.baseArgInfos(bc)) || + tyconOK(tp1w.baseTypeTycon(bc), tp1w.baseArgInfos(bc)) || liftToBase(bcs1) case _ => false @@ -771,7 +771,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tycon1 match { case param1: TypeParamRef => def canInstantiate = tp2 match { - case AppliedType(tycon2, args2) => + case AnyAppliedType(tycon2, args2) => tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams) case _ => false @@ -810,7 +810,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val classBounds = tp2.classSymbols def recur(bcs: List[ClassSymbol]): Boolean = bcs match { case bc :: bcs1 => - val baseRef = tp1.baseTypeRef(bc) + val baseRef = tp1.baseTypeTycon(bc) (classBounds.exists(bc.derivesFrom) && variancesConform(baseRef.typeParams, tparams) && p(baseRef.appliedTo(tp1.baseArgInfos(bc))) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 829b5acec00c..73f57131646f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -66,7 +66,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. else pre match { case pre: SuperType => toPrefix(pre.thistpe, cls, thiscls) case _ => - if (thiscls.derivesFrom(cls) && pre.baseTypeRef(thiscls).exists) { + if (thiscls.derivesFrom(cls) && pre.baseType(thiscls).exists) { // ??? why not derivesFrom ??? if (theMap != null && theMap.currentVariance <= 0 && !isLegalPrefix(pre)) { ctx.base.unsafeNonvariant = ctx.runId pre match { @@ -79,7 +79,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. else if ((pre.termSymbol is Package) && !(thiscls is Package)) toPrefix(pre.select(nme.PACKAGE), cls, thiscls) else - toPrefix(pre.baseTypeRef(cls).normalizedPrefix, cls.owner, thiscls) + toPrefix(pre.baseType(cls).normalizedPrefix, cls.owner, thiscls) } } @@ -256,7 +256,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. val doms = dominators(commonBaseClasses, Nil) def baseTp(cls: ClassSymbol): Type = { val base = - if (tp1.typeParams.nonEmpty) tp.baseTypeRef(cls) + if (tp1.typeParams.nonEmpty) tp.baseTypeTycon(cls) else tp.baseTypeWithArgs(cls) base.mapReduceOr(identity)(mergeRefined) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 40fbc80f85f0..bf2ec82db404 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -566,6 +566,7 @@ object Types { try pdenot.info & rinfo catch { case ex: CyclicReference => + // ??? can this still happen? ??? // happens for tests/pos/sets.scala. findMember is called from baseTypeRef. // The & causes a subtype check which calls baseTypeRef again with the same // superclass. In the observed case, the superclass was Any, and @@ -826,13 +827,17 @@ object Types { /** The basetype TypeRef of this type with given class symbol, * but without including any type arguments */ - final def baseTypeRef(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseTypeRef $base")*/ /*>|>*/ track("baseTypeRef") /*<|<*/ { + final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("baseType") /*<|<*/ { base.denot match { - case classd: ClassDenotation => classd.baseTypeRefOf(this) + case classd: ClassDenotation => classd.baseTypeOf(this) case _ => NoType } } + /** Temporary replacement for baseTypeRef */ + final def baseTypeTycon(base: Symbol)(implicit ctx: Context): Type = + baseType(base).typeConstructor + def & (that: Type)(implicit ctx: Context): Type = track("&") { ctx.typeComparer.glb(this, that) } @@ -1001,6 +1006,12 @@ object Types { case _ => this } + /** The type constructor of an applied type, otherwise the type itself */ + final def typeConstructor(implicit ctx: Context): Type = this match { + case AppliedType(tycon, _) => tycon + case _ => this + } + /** If this is a (possibly aliased, annotated, and/or parameterized) reference to * a class, the class type ref, otherwise NoType. * @param refinementOK If `true` we also skip non-parameter refinements. @@ -1435,6 +1446,11 @@ object Types { /** A marker trait for types that can be types of values or that are higher-kinded */ trait ValueType extends ValueTypeOrProto with ValueTypeOrWildcard + /** A common base trait of NamedType and AppliedType */ + trait RefType extends CachedProxyType with ValueType { + def symbol(implicit ctx: Context): Symbol + } + /** A marker trait for types that are guaranteed to contain only a * single non-null value (they might contain null in addition). */ @@ -1466,7 +1482,7 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ /** A NamedType of the form Prefix # name */ - abstract class NamedType extends CachedProxyType with ValueType { + abstract class NamedType extends CachedProxyType with RefType { val prefix: Type val name: Name @@ -2994,6 +3010,91 @@ object Types { def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n) } + /** A type application `C[T_1, ..., T_n]` */ + abstract case class AppliedType(tycon: Type, args: List[Type]) + extends CachedProxyType with RefType { + + private var validSuper: Period = Nowhere + private var cachedSuper: Type = _ + + override def underlying(implicit ctx: Context): Type = tycon + + override def superType(implicit ctx: Context): Type = { + def reapply(tp: Type) = tp match { + case tp: TypeRef if tp.symbol.isClass => tp + case _ => tp.applyIfParameterized(args) + } + if (ctx.period != validSuper) { + validSuper = ctx.period + cachedSuper = tycon match { + case tp: HKTypeLambda => defn.AnyType + case tp: TypeVar if !tp.inst.exists => + // supertype not stable, since underlying might change + validSuper = Nowhere + reapply(tp.underlying) + case tp: TypeProxy => + if (tp.typeSymbol.is(Provisional)) validSuper = Nowhere + reapply(tp.superType) + case _ => defn.AnyType + } + } + cachedSuper + } + + override def symbol(implicit ctx: Context) = tycon.typeSymbol + + def lowerBound(implicit ctx: Context) = tycon.stripTypeVar match { + case tycon: TypeRef => + tycon.info match { + case TypeBounds(lo, hi) => + if (lo eq hi) superType // optimization, can profit from caching in this case + else lo.applyIfParameterized(args) + case _ => NoType + } + case _ => + NoType + } + + def typeParams(implicit ctx: Context): List[ParamInfo] = { + val tparams = tycon.typeParams + if (tparams.isEmpty) HKTypeLambda.any(args.length).typeParams else tparams + } + + def derivedAppliedType(tycon: Type, args: List[Type])(implicit ctx: Context): Type = + if ((tycon eq this.tycon) && (args eq this.args)) this + else tycon.appliedTo(args) + + override def computeHash = doHash(tycon, args) + + protected def checkInst(implicit ctx: Context): this.type = { + def check(tycon: Type): Unit = tycon.stripTypeVar match { + case tycon: TypeRef => + case _: TypeParamRef | _: ErrorType | _: WildcardType => + case _: TypeLambda => + assert(!args.exists(_.isInstanceOf[TypeBounds]), s"unreduced type apply: $this") + case tycon: AnnotatedType => + check(tycon.underlying) + case _ => + assert(false, s"illegal type constructor in $this") + } + if (Config.checkHKApplications) check(tycon) + this + } + } + + final class CachedAppliedType(tycon: Type, args: List[Type]) extends AppliedType(tycon, args) + + object AppliedType { + def apply(tycon: Type, args: List[Type])(implicit ctx: Context) = + unique(new CachedAppliedType(tycon, args)).checkInst + } + + object ClassRef { + def unapply(tp: RefType)(implicit ctx: Context): Option[RefType] = { // after bootstrap, drop the Option + if (tp.symbol.isClass) Some(tp) else None + } + } + /** A higher kinded type application `C[T_1, ..., T_n]` */ abstract case class HKApply(tycon: Type, args: List[Type]) extends CachedProxyType with ValueType { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 338a395ab685..3b8789ada24a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -139,7 +139,7 @@ class TreePickler(pickler: TastyPickler) { } private def pickleNewType(tpe: Type, richTypes: Boolean)(implicit ctx: Context): Unit = tpe match { - case AppliedType(tycon, args) => + case AnyAppliedType(tycon, args) => writeByte(APPLIEDtype) withLength { pickleType(tycon); args.foreach(pickleType(_)) } case ConstantType(value) => diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 8a10ef60ebbe..91eabe742839 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -4,7 +4,7 @@ package printing import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, Denotations._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation -import TypeApplications.AppliedType +import TypeApplications.AnyAppliedType import StdNames.{nme, tpnme} import ast.Trees._, ast._ import typer.Implicits._ @@ -123,7 +123,7 @@ class PlainPrinter(_ctx: Context) extends Printer { */ private def refinementChain(tp: Type): List[Type] = tp :: (tp match { - case AppliedType(_, _) => Nil + case AnyAppliedType(_, _) => Nil case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) case _ => Nil }) @@ -142,7 +142,7 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" case tp: TypeRef => toTextPrefix(tp.prefix) ~ selectionString(tp) - case AppliedType(tycon, args) => + case AnyAppliedType(tycon, args) => (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: RefinedType => val parent :: (refined: List[RefinedType @unchecked]) = diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index c494110201e4..482d8c651cce 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -126,7 +126,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } def isInfixType(tp: Type): Boolean = tp match { - case AppliedType(tycon, args) => + case AnyAppliedType(tycon, args) => args.length == 2 && !Character.isUnicodeIdentifierStart(tycon.typeSymbol.name.toString.head) // TODO: Once we use the 2.12 stdlib, also check the @showAsInfix annotation @@ -149,7 +149,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { homogenize(tp) match { case x: ConstantType if homogenizedView => return toText(x.widen) - case AppliedType(tycon, args) => + case AnyAppliedType(tycon, args) => val cls = tycon.typeSymbol if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 5488d1979649..b499427d5009 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -370,7 +370,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder else tp.prefix new api.Projection(simpleType(prefix), sym.name.toString) - case TypeApplications.AppliedType(tycon, args) => + case TypeApplications.AnyAppliedType(tycon, args) => def processArg(arg: Type): api.Type = arg match { case arg @ TypeBounds(lo, hi) => // Handle wildcard parameters if (lo.isDirectRef(defn.NothingClass) && hi.isDirectRef(defn.AnyClass)) diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 937490ab060a..3ad2d69305c9 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -105,7 +105,7 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf for (parentTrait <- cls.mixins) { if (needsOuterIfReferenced(parentTrait)) { - val parentTp = cls.denot.thisType.baseTypeRef(parentTrait) + val parentTp = cls.denot.thisType.baseType(parentTrait) val outerAccImpl = newOuterAccessor(cls, parentTrait).enteredAfter(thisTransformer) newDefs += DefDef(outerAccImpl, singleton(fixThis(outerPrefix(parentTp)))) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 46640b02c021..34f86aa14249 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -377,12 +377,12 @@ trait Applications extends Compatibility { self: Typer with Dynamic => // default getters for class constructors are found in the companion object val cls = meth.owner val companion = cls.companionModule - receiver.tpe.baseTypeRef(cls) match { - case tp: TypeRef if companion.isTerm => - selectGetter(ref(TermRef(tp.prefix, companion.asTerm))) - case _ => - EmptyTree + if (companion.isTerm) { + val prefix = receiver.tpe.baseType(cls).normalizedPrefix + if (prefix.exists) selectGetter(ref(TermRef(prefix, companion.asTerm))) + else EmptyTree } + else EmptyTree } } } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 2e84a2389a9f..e2cebaf00777 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -921,7 +921,7 @@ class Namer { typer: Typer => Checking.checkWellFormed(cls) if (isDerivedValueClass(cls)) cls.setFlag(Final) cls.info = avoidPrivateLeaks(cls, cls.pos) - cls.baseClasses.foreach(_.invalidateBaseTypeRefCache()) // we might have looked before and found nothing + cls.baseClasses.foreach(_.invalidateBaseTypeCache()) // we might have looked before and found nothing } } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 3a330b3f041d..ea115a07a3a1 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -6,7 +6,7 @@ import core._ import ast._ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ -import TypeApplications.AppliedType +import TypeApplications.AnyAppliedType import util.Positions._ import config.Printers.typr import ast.Trees._ @@ -104,7 +104,7 @@ trait TypeAssigner { } case tp @ HKApply(tycon, args) if toAvoid(tycon) => apply(tp.superType) - case tp @ AppliedType(tycon, args) if toAvoid(tycon) => + case tp @ AnyAppliedType(tycon, args) if toAvoid(tycon) => val base = apply(tycon) var args = tp.baseArgInfos(base.typeSymbol) if (base.typeParams.length != args.length) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 03f11335ead1..563a20938372 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -57,7 +57,7 @@ object factories { } def expandTpe(t: Type, params: List[Reference] = Nil): Reference = t match { - case AppliedType(tycon, args) => { + case AnyAppliedType(tycon, args) => { val cls = tycon.typeSymbol if (defn.isFunctionClass(cls)) From 140fac30c24280cfb4ce398140b37cb91ecfc6a2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Jul 2017 16:34:45 +0200 Subject: [PATCH 2/3] Adapt operations in Types So far, everything up to parents is adapted to new scheme. Parents is half done; needs more work once we change layour of ClassInfo. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +- .../tools/dotc/core/SymDenotations.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 76 +++++++++++++------ .../tools/dotc/printing/PlainPrinter.scala | 4 +- .../dotc/reporting/diagnostic/messages.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotc/transform/OverridingPairs.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- 11 files changed, 66 insertions(+), 36 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 016db8e2c01b..4ee30af5ede1 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -213,7 +213,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { ta.assignType(untpd.TypeDef(sym.name, TypeTree(sym.info)), sym) def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = { - val firstParentRef :: otherParentRefs = cls.info.parents + val firstParentRef :: otherParentRefs = cls.info.parentRefs val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol) val superRef = if (cls is Trait) TypeTree(firstParent) @@ -261,7 +261,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def AnonClass(parents: List[Type], fns: List[TermSymbol], methNames: List[TermName])(implicit ctx: Context): Block = { val owner = fns.head.owner val parents1 = - if (parents.head.classSymbol.is(Trait)) parents.head.parents.head :: parents + if (parents.head.classSymbol.is(Trait)) parents.head.parentRefs.head :: parents else parents val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1, coord = fns.map(_.pos).reduceLeft(_ union _)) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 6c3204eaacfb..3bd592a9b181 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1620,7 +1620,7 @@ object SymDenotations { tp else subcls.denot match { case cdenot: ClassDenotation => - if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parents) + if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parentsNEW) // !!! change to parents else NoType case _ => baseTypeOf(tp.superType) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bf2ec82db404..12c3680bd697 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -129,9 +129,10 @@ object Types { case TypeAlias(tp) => assert((tp ne this) && (tp ne this1), s"$tp / $this") tp.isRef(sym) - case _ => this1.symbol eq sym + case _ => this1.symbol eq sym } case this1: RefinedOrRecType => this1.parent.isRef(sym) + case this1: AppliedType => this1.underlying.isRef(sym) case this1: HKApply => this1.superType.isRef(sym) case _ => false } @@ -210,7 +211,7 @@ object Types { */ private final def phantomLatticeType(implicit ctx: Context): Type = widen match { case tp: ClassInfo if defn.isPhantomTerminalClass(tp.classSymbol) => tp.prefix - case tp: TypeProxy if tp.superType ne this => tp.underlying.phantomLatticeType + case tp: TypeProxy if tp.superType ne this => tp.underlying.phantomLatticeType // ??? guard needed ??? case tp: AndOrType => tp.tp1.phantomLatticeType case _ => NoType } @@ -483,6 +484,8 @@ object Types { }) case tp: TypeRef => tp.denot.findMember(name, pre, excluded) + case tp: AppliedType => + goApplied(tp) case tp: ThisType => goThis(tp) case tp: RefinedType => @@ -494,7 +497,7 @@ object Types { case tp: SuperType => goSuper(tp) case tp: HKApply => - goApply(tp) + goHKApply(tp) case tp: TypeProxy => go(tp.underlying) case tp: ClassInfo => @@ -584,7 +587,15 @@ object Types { } } - def goApply(tp: HKApply) = tp.tycon match { + def goApplied(tp: AppliedType) = tp.tycon match { + case tl: HKTypeLambda => + go(tl.resType).mapInfo(info => + tl.derivedLambdaAbstraction(tl.paramNames, tl.paramInfos, info).appliedTo(tp.args)) + case _ => + go(tp.superType) + } + + def goHKApply(tp: HKApply) = tp.tycon match { case tl: HKTypeLambda => go(tl.resType).mapInfo(info => tl.derivedLambdaAbstraction(tl.paramNames, tl.paramInfos, info).appliedTo(tp.args)) @@ -963,6 +974,14 @@ object Types { case TypeAlias(tp) => tp.dealias(keepAnnots): @tailrec case _ => tp } + case app @ AppliedType(tycon, args) => + val tycon1 = tycon.dealias(keepAnnots) + if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec + else this + case app @ HKApply(tycon, args) => + val tycon1 = tycon.dealias(keepAnnots) + if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec + else this case tp: TypeVar => val tp1 = tp.instanceOpt if (tp1.exists) tp1.dealias(keepAnnots): @tailrec else tp @@ -971,10 +990,6 @@ object Types { if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1 case tp: LazyRef => tp.ref.dealias(keepAnnots): @tailrec - case app @ HKApply(tycon, args) => - val tycon1 = tycon.dealias(keepAnnots) - if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec - else this case _ => this } @@ -1021,6 +1036,8 @@ object Types { if (tp.symbol.isClass) tp else if (tp.symbol.isAliasType) tp.underlying.underlyingClassRef(refinementOK) else NoType + case tp: AppliedType => + tp.superType.underlyingClassRef(refinementOK) case tp: AnnotatedType => tp.underlying.underlyingClassRef(refinementOK) case tp: RefinedType => @@ -1158,19 +1175,33 @@ object Types { * Inherited by all type proxies. Empty for all other types. * Overwritten in ClassInfo, where parents is cached. */ - def parents(implicit ctx: Context): List[TypeRef] = this match { - case tp: TypeProxy => tp.underlying.parents - case _ => List() + def parentRefs(implicit ctx: Context): List[TypeRef] = this match { + case tp: TypeProxy => tp.underlying.parentRefs + case _ => Nil } /** The full parent types, including all type arguments */ def parentsWithArgs(implicit ctx: Context): List[Type] = this match { case tp: TypeProxy => tp.superType.parentsWithArgs - case _ => List() + case _ => Nil + } + + /** The full parent types, including (in new scheme) all type arguments */ + def parentsNEW(implicit ctx: Context): List[Type] = this match { + case AppliedType(tycon: HKTypeLambda, args) => // TODO: can be eliminated once ClassInfo is changed, also: cache? + tycon.resType.parentsWithArgs.map(_.substParams(tycon, args)) + case tp: TypeProxy => tp.superType.parentsNEW + case _ => Nil + } + + /** The first parent of this type, AnyRef if list of parents is empty */ + def firstParentRef(implicit ctx: Context): TypeRef = parentRefs match { + case p :: _ => p + case _ => defn.AnyType } /** The first parent of this type, AnyRef if list of parents is empty */ - def firstParent(implicit ctx: Context): TypeRef = parents match { + def firstParentNEW(implicit ctx: Context): Type = parentsNEW match { case p :: _ => p case _ => defn.AnyType } @@ -3020,10 +3051,6 @@ object Types { override def underlying(implicit ctx: Context): Type = tycon override def superType(implicit ctx: Context): Type = { - def reapply(tp: Type) = tp match { - case tp: TypeRef if tp.symbol.isClass => tp - case _ => tp.applyIfParameterized(args) - } if (ctx.period != validSuper) { validSuper = ctx.period cachedSuper = tycon match { @@ -3031,10 +3058,10 @@ object Types { case tp: TypeVar if !tp.inst.exists => // supertype not stable, since underlying might change validSuper = Nowhere - reapply(tp.underlying) + tp.underlying.applyIfParameterized(args) case tp: TypeProxy => if (tp.typeSymbol.is(Provisional)) validSuper = Nowhere - reapply(tp.superType) + tp.superType.applyIfParameterized(args) case _ => defn.AnyType } } @@ -3441,7 +3468,7 @@ object Types { private var parentsCache: List[TypeRef] = null /** The parent type refs as seen from the given prefix */ - override def parents(implicit ctx: Context): List[TypeRef] = { + override def parentRefs(implicit ctx: Context): List[TypeRef] = { if (parentsCache == null) parentsCache = cls.classParents.mapConserve(_.asSeenFrom(prefix, cls.owner).asInstanceOf[TypeRef]) parentsCache @@ -3449,7 +3476,7 @@ object Types { /** The parent types with all type arguments */ override def parentsWithArgs(implicit ctx: Context): List[Type] = - parents mapConserve { pref => + parentRefs mapConserve { pref => ((pref: Type) /: pref.classSymbol.typeParams) { (parent, tparam) => val targSym = decls.lookup(tparam.name) if (targSym.exists) RefinedType(parent, targSym.name, targSym.info) @@ -3457,6 +3484,9 @@ object Types { } } + override def parentsNEW(implicit ctx: Context): List[Type] = + parentRefs // !!! TODO: change + def derivedClassInfo(prefix: Type)(implicit ctx: Context) = if (prefix eq this.prefix) this else ClassInfo(prefix, cls, classParents, decls, selfInfo) @@ -3929,12 +3959,12 @@ object Types { abstract class DeepTypeMap(implicit ctx: Context) extends TypeMap { override def mapClassInfo(tp: ClassInfo) = { val prefix1 = this(tp.prefix) - val parents1 = (tp.parents mapConserve this).asInstanceOf[List[TypeRef]] + val parentRefs1 = (tp.parentRefs mapConserve this).asInstanceOf[List[TypeRef]] val selfInfo1 = tp.selfInfo match { case selfInfo: Type => this(selfInfo) case selfInfo => selfInfo } - tp.derivedClassInfo(prefix1, parents1, tp.decls, selfInfo1) + tp.derivedClassInfo(prefix1, parentRefs1, tp.decls, selfInfo1) } } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 91eabe742839..cf409a18103b 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -323,7 +323,7 @@ class PlainPrinter(_ctx: Context) extends Printer { val declsText = if (trueDecls.isEmpty || !ctx.settings.debug.value) Text() else dclsText(trueDecls) - tparamsText ~ " extends " ~ toTextParents(tp.parents) ~ "{" ~ selfText ~ declsText ~ + tparamsText ~ " extends " ~ toTextParents(tp.parentsNEW) ~ "{" ~ selfText ~ declsText ~ "} at " ~ preText case tp => ": " ~ toTextGlobal(tp) @@ -401,7 +401,7 @@ class PlainPrinter(_ctx: Context) extends Printer { def toText(sym: Symbol): Text = (kindString(sym) ~~ { - if (sym.isAnonymousClass) toText(sym.info.parents, " with ") ~ "{...}" + if (sym.isAnonymousClass) toText(sym.info.parentsNEW, " with ") ~ "{...}" else if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym) else nameString(sym) }).close diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index af0861ad6bf2..312793035e15 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1258,7 +1258,7 @@ object messages { val msg = hl"""|$qual does not name a parent of $cls""" val kind = "Reference" - private val parents: Seq[String] = (cls.info.parents map (_.name.show)).sorted + private val parents: Seq[String] = (cls.info.parentRefs map (_.name.show)).sorted val explanation = hl"""|When a qualifier ${"T"} is used in a ${"super"} prefix of the form ${"C.super[T]"}, diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 5837b2b6904a..25c8c53a37a1 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -391,7 +391,7 @@ object Erasure { cpy.Super(qual)(thisQual, untpd.Ident(sym.owner.asClass.name)) .withType(SuperType(thisType, sym.owner.typeRef)) else - qual.withType(SuperType(thisType, thisType.firstParent)) + qual.withType(SuperType(thisType, thisType.firstParentRef)) case _ => qual } diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 3ad2d69305c9..8573e1e930d9 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -194,7 +194,7 @@ object ExplicitOuter { needsOuterIfReferenced(cls) && (!hasLocalInstantiation(cls) || // needs outer because we might not know whether outer is referenced or not cls.mixins.exists(needsOuterIfReferenced) || // needs outer for parent traits - cls.classInfo.parents.exists(parent => // needs outer to potentially pass along to parent + cls.info.parentsNEW.exists(parent => // needs outer to potentially pass along to parent needsOuterIfReferenced(parent.classSymbol.asClass))) /** Class is always instantiated in the compilation unit where it is defined */ diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index cbd79d5c50d6..44c17d15178c 100644 --- a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -35,7 +35,7 @@ object OverridingPairs { * pair has already been treated in a parent class. * This may be refined in subclasses. @see Bridges for a use case. */ - protected def parents: Array[Symbol] = base.info.parents.toArray map (_.typeSymbol) + protected def parents: Array[Symbol] = base.info.parentsNEW.toArray map (_.typeSymbol) /** Does `sym1` match `sym2` so that it qualifies as overriding. * Types always match. Term symbols match if their membertypes diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 34f86aa14249..be6c2793783d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -891,7 +891,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean = if (subtp <:< tp) true else tp match { - case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParent) + case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParentNEW) case tp: TypeProxy => isSubTypeOfParent(subtp, tp.superType) case _ => false } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 97d50b07e34e..7a7f8d9df998 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -285,7 +285,7 @@ object RefChecks { //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG return } - val parentSymbols = clazz.info.parents.map(_.typeSymbol) + val parentSymbols = clazz.info.parentsNEW.map(_.typeSymbol) if (parentSymbols exists (p => subOther(p) && subMember(p) && deferredCheck)) { //Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG return diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index ea115a07a3a1..2e5cdfb55acf 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -293,7 +293,7 @@ trait TypeAssigner { case err: ErrorType => untpd.cpy.Super(tree)(qual, mix).withType(err) case qtype @ ThisType(_) => val cls = qtype.cls - def findMixinSuper(site: Type): Type = site.parents filter (_.name == mix.name) match { + def findMixinSuper(site: Type): Type = site.parentRefs filter (_.name == mix.name) match { case p :: Nil => p case Nil => @@ -304,7 +304,7 @@ trait TypeAssigner { val owntype = if (mixinClass.exists) mixinClass.typeRef else if (!mix.isEmpty) findMixinSuper(cls.info) - else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent + else if (inConstrCall || ctx.erasedTypes) cls.info.firstParentRef else { val ps = cls.classInfo.parentsWithArgs if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y) From 1f1d8953d1f92ad476142dea295e3decae0c1e4c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jul 2017 14:29:02 +0200 Subject: [PATCH 3/3] Move givenSelfType to ClassSymbol Simplifies usage and removes some obscure code in Types --- .../backend/jvm/DottyBackendInterface.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 8 ++++++ .../src/dotty/tools/dotc/core/Types.scala | 28 ++++--------------- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- .../tools/dotc/transform/ExplicitSelf.scala | 5 ++-- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../dotty/tools/dotc/typer/RefChecks.scala | 8 +++--- .../dotty/tools/dotc/typer/TypeAssigner.scala | 20 ++++++------- 8 files changed, 31 insertions(+), 44 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 297f7e0f8934..aacee60668ff 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -889,7 +889,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma // to inner symbols of DefDef // todo: somehow handle. - def parents: List[Type] = tp.parents + def parents: List[Type] = tp.parentsNEW } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3bd592a9b181..54d7d41d3206 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1379,6 +1379,14 @@ object SymDenotations { NoSymbol } + /** The explicitly given self type (self types of modules are assumed to be + * explcitly given here). + */ + def givenSelfType(implicit ctx: Context) = classInfo.selfInfo match { + case tp: Type => tp + case self: Symbol => self.info + } + // ------ class-specific operations ----------------------------------- private[this] var myThisType: Type = null diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 12c3680bd697..683ae0a0d08f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1206,14 +1206,6 @@ object Types { case _ => defn.AnyType } - /** the self type of the underlying classtype */ - def givenSelfType(implicit ctx: Context): Type = this match { - case tp: RefinedType => tp.wrapIfMember(tp.parent.givenSelfType) - case tp: ThisType => tp.tref.givenSelfType - case tp: TypeProxy => tp.superType.givenSelfType - case _ => NoType - } - /** The parameter types of a PolyType or MethodType, Empty list for others */ final def paramInfoss(implicit ctx: Context): List[List[Type]] = stripPoly match { case mt: MethodType => mt.paramInfos :: mt.resultType.paramInfoss @@ -1642,10 +1634,8 @@ object Types { } private def checkSymAssign(sym: Symbol)(implicit ctx: Context) = { - def selfTypeOf(sym: Symbol) = sym.owner.info match { - case info: ClassInfo => info.givenSelfType - case _ => NoType - } + def selfTypeOf(sym: Symbol) = + if (sym.isClass) sym.asClass.givenSelfType else NoType assert( (lastSymbol eq sym) || @@ -2244,7 +2234,7 @@ object Types { if ((parent eq this.parent) && (refinedName eq this.refinedName) && (refinedInfo eq this.refinedInfo)) this else RefinedType(parent, refinedName, refinedInfo) - /** Add this refinement to `parent`, provided If `refinedName` is a member of `parent`. */ + /** Add this refinement to `parent`, provided `refinedName` is a member of `parent`. */ def wrapIfMember(parent: Type)(implicit ctx: Context): Type = if (parent.member(refinedName).exists) derivedRefinedType(parent, refinedName, refinedInfo) else parent @@ -3418,7 +3408,7 @@ object Types { if (selfTypeCache == null) selfTypeCache = { def fullRef = fullyAppliedRef - val given = givenSelfType + val given = cls.givenSelfType val raw = if (!given.exists) fullRef else if (cls is Module) given @@ -3429,14 +3419,6 @@ object Types { selfTypeCache } - /** The explicitly given self type (self types of modules are assumed to be - * explcitly given here). - */ - override def givenSelfType(implicit ctx: Context): Type = selfInfo match { - case tp: Type => tp - case self: Symbol => self.info - } - private var selfTypeCache: Type = null private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match { @@ -4275,7 +4257,7 @@ object Types { } private def otherReason(pre: Type)(implicit ctx: Context): String = pre match { - case pre: ThisType if pre.givenSelfType.exists => + case pre: ThisType if pre.cls.givenSelfType.exists => i"\nor the self type of $pre might not contain all transitive dependencies" case _ => "" } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index b499427d5009..b34eade299ee 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -179,7 +179,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder else dt.Module } else dt.ClassDef - val selfType = apiType(sym.classInfo.givenSelfType) + val selfType = apiType(sym.givenSelfType) val name = if (sym.is(ModuleClass)) sym.fullName.sourceModuleName else sym.fullName diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala index 7bb65e5755b2..3592471823ff 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitSelf.scala @@ -38,9 +38,8 @@ class ExplicitSelf extends MiniPhaseTransform { thisTransform => override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { case Select(thiz: This, name) if name.isTermName => val cls = thiz.symbol.asClass - val cinfo = cls.classInfo - if (cinfo.givenSelfType.exists && !cls.derivesFrom(tree.symbol.owner)) - cpy.Select(tree)(thiz.asInstance(AndType(cinfo.selfType, thiz.tpe)), name) + if (cls.givenSelfType.exists && !cls.derivesFrom(tree.symbol.owner)) + cpy.Select(tree)(thiz.asInstance(AndType(cls.classInfo.selfType, thiz.tpe)), name) else tree case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 72ce89a33942..2dfb3f7aadc9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -133,7 +133,7 @@ object Checking { // Create a synthetic singleton type instance, and check whether // it conforms to the self type of the class as seen from that instance. val stp = SkolemType(tp) - val selfType = tref.givenSelfType.asSeenFrom(stp, cls) + val selfType = cls.asClass.givenSelfType.asSeenFrom(stp, cls) if (selfType.exists && !(stp <:< selfType)) ctx.error(DoesNotConformToSelfTypeCantBeInstantiated(tp, selfType), pos) } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 7a7f8d9df998..741e174d3ec2 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -94,16 +94,16 @@ object RefChecks { */ private def checkParents(cls: Symbol)(implicit ctx: Context): Unit = cls.info match { case cinfo: ClassInfo => - def checkSelfConforms(other: TypeRef, category: String, relation: String) = { + def checkSelfConforms(other: ClassSymbol, category: String, relation: String) = { val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol) if (otherSelf.exists && !(cinfo.selfType <:< otherSelf)) ctx.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), cls.pos) } for (parent <- cinfo.classParents) - checkSelfConforms(parent, "illegal inheritance", "parent") - for (reqd <- cinfo.givenSelfType.classSymbols) - checkSelfConforms(reqd.typeRef, "missing requirement", "required") + checkSelfConforms(parent.typeSymbol.asClass, "illegal inheritance", "parent") + for (reqd <- cinfo.cls.givenSelfType.classSymbols) + checkSelfConforms(reqd, "missing requirement", "required") case _ => } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 2e5cdfb55acf..6f2fe09fa887 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -513,17 +513,15 @@ trait TypeAssigner { private def symbolicIfNeeded(sym: Symbol)(implicit ctx: Context) = { val owner = sym.owner - owner.infoOrCompleter match { - case info: ClassInfo if info.givenSelfType.exists => - // In that case a simple typeRef/termWithWithSig could return a member of - // the self type, not the symbol itself. To avoid this, we make the reference - // symbolic. In general it seems to be faster to keep the non-symblic - // reference, since there is less pressure on the uniqueness tables that way - // and less work to update all the different references. That's why symbolic references - // are only used if necessary. - NamedType.withFixedSym(owner.thisType, sym) - case _ => NoType - } + if (owner.isClass && owner.isCompleted && owner.asClass.givenSelfType.exists) + // In that case a simple typeRef/termWithWithSig could return a member of + // the self type, not the symbol itself. To avoid this, we make the reference + // symbolic. In general it seems to be faster to keep the non-symblic + // reference, since there is less pressure on the uniqueness tables that way + // and less work to update all the different references. That's why symbolic references + // are only used if necessary. + NamedType.withFixedSym(owner.thisType, sym) + else NoType } def assertExists(tp: Type) = { assert(tp != NoType); tp }