From 8fa29ad906a0f9b3a7de64d63616ebab6418e466 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Jul 2017 13:44:35 +0200 Subject: [PATCH 001/146] 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 | 2 +- .../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 | 2 +- .../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 | 2 +- .../tools/dottydoc/model/factories.scala | 2 +- 14 files changed, 164 insertions(+), 61 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 473ae32f9dc1..8a88d4c96c9e 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 )) @@ -1269,10 +1269,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 @@ -1285,14 +1285,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() = { @@ -1305,9 +1305,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 = { @@ -1316,7 +1316,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 _ => } @@ -1584,11 +1584,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 } @@ -1600,7 +1600,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 @@ -1612,12 +1612,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 @@ -1626,14 +1626,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 _ => @@ -1641,16 +1641,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) @@ -1662,7 +1662,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 9397eeb09d7b..f68d24e36d94 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 7dec61044aa9..09a476c8c9cb 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 } @@ -716,7 +716,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 @@ -774,7 +774,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 @@ -813,7 +813,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 a426fa5c1d53..9f172243f37d 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -185,7 +185,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 32ce37b10a9f..ab818010c31c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -573,6 +573,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 @@ -833,13 +834,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) } @@ -1008,6 +1013,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. @@ -1454,6 +1465,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). */ @@ -1485,7 +1501,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 @@ -3012,6 +3028,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 add58d0d73ad..15d6f37f0dba 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._ @@ -133,7 +133,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 }) @@ -152,7 +152,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 49da2dc136ee..e4db012bc0dd 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -141,7 +141,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 548824ce2684..e9d9f1233756 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -382,12 +382,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 7b2801670ae6..0993e30cd4d9 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -922,7 +922,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 fe3b80f3417f..58a10500c1b1 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._ 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 7be50a668cc499d424c1b7089b0b34cc2ca5fa5a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Jul 2017 16:34:45 +0200 Subject: [PATCH 002/146] 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 | 79 +++++++++++++------ .../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, 69 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 8a88d4c96c9e..de3b3f89d8fa 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1623,7 +1623,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 ab818010c31c..0523f678623e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -129,9 +129,13 @@ 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 => + val this2 = this1.dealias + if (this2 ne this1) this2.isRef(sym) + else this1.underlying.isRef(sym) case this1: HKApply => val this2 = this1.dealias if (this2 ne this1) this2.isRef(sym) @@ -227,7 +231,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 } @@ -490,6 +494,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 => @@ -501,7 +507,7 @@ object Types { case tp: SuperType => goSuper(tp) case tp: HKApply => - goApply(tp) + goHKApply(tp) case tp: TypeProxy => go(tp.underlying) case tp: ClassInfo => @@ -591,7 +597,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)) @@ -970,6 +984,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 @@ -978,10 +1000,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 } @@ -1028,6 +1046,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 => @@ -1165,19 +1185,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 firstParent(implicit ctx: Context): TypeRef = parents match { + 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 firstParentNEW(implicit ctx: Context): Type = parentsNEW match { case p :: _ => p case _ => defn.AnyType } @@ -3038,10 +3072,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 { @@ -3049,10 +3079,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 } } @@ -3459,7 +3489,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 @@ -3467,7 +3497,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) @@ -3475,6 +3505,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) @@ -3959,12 +3992,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 15d6f37f0dba..3f3bd6e852e2 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -333,7 +333,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) @@ -411,7 +411,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 6bd4069fc2a9..64717e980e61 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1284,7 +1284,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 0fa79214ddc8..f32d0b8a591a 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -409,7 +409,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 e9d9f1233756..d79501c1cae0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -915,7 +915,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 58a10500c1b1..f726cb1cb460 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -297,7 +297,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 => @@ -308,7 +308,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 2ec644be1333ebc2e88c1909d6f21f9aca917126 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 22 Jul 2017 14:29:02 +0200 Subject: [PATCH 003/146] 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 40b8412308a4..7831260e1bc5 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -897,7 +897,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 } object Assign extends AssignDeconstructor { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index de3b3f89d8fa..2fcc57cbbaf2 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1382,6 +1382,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 0523f678623e..17b45e9e4a29 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1216,14 +1216,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 @@ -1664,10 +1656,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) || @@ -2265,7 +2255,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 @@ -3439,7 +3429,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 @@ -3450,14 +3440,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 { @@ -4452,7 +4434,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 a79cff397dbf..4ebef4900d7d 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 f726cb1cb460..b8706b953aa1 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -517,17 +517,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 } From b219c74653fc12d2b3d860cd621586c4199d1965 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 23 Jul 2017 11:56:29 +0200 Subject: [PATCH 004/146] Handle AppliedTypes Systematically introduce handlers for AppliedTypes where there was a handler for HKApply. --- .../src/dotty/tools/dotc/config/Config.scala | 2 + .../tools/dotc/core/SymDenotations.scala | 1 + .../tools/dotc/core/TypeApplications.scala | 6 +- .../dotty/tools/dotc/core/TypeComparer.scala | 226 +++++++++++++++++- .../dotty/tools/dotc/core/TypeErasure.scala | 8 +- .../src/dotty/tools/dotc/core/TypeOps.scala | 81 ++++--- .../src/dotty/tools/dotc/core/Types.scala | 75 +++++- .../dotc/core/classfile/ClassfileParser.scala | 4 +- .../core/unpickleScala2/Scala2Unpickler.scala | 8 + .../tools/dotc/printing/PlainPrinter.scala | 4 + .../tools/dotc/transform/patmat/Space.scala | 5 + .../src/dotty/tools/dotc/typer/Checking.scala | 23 +- .../dotty/tools/dotc/typer/Implicits.scala | 7 + .../dotty/tools/dotc/typer/ProtoTypes.scala | 5 + .../dotty/tools/dotc/typer/Variances.scala | 11 + .../tools/dottydoc/model/factories.scala | 2 +- 16 files changed, 413 insertions(+), 55 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index ffc4d65632cf..22f36dfea790 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -174,4 +174,6 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true + + final val newScheme = false } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 2fcc57cbbaf2..64d45c30b696 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1174,6 +1174,7 @@ object SymDenotations { case tp: TypeBounds => hasSkolems(tp.lo) || hasSkolems(tp.hi) case tp: TypeVar => hasSkolems(tp.inst) case tp: ExprType => hasSkolems(tp.resType) + case tp: AppliedType => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType) case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index f68d24e36d94..199b63e24880 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -185,7 +185,7 @@ object TypeApplications { case arg => arg } - case _: TypeBounds | _: HKApply => + case _: TypeBounds | _: HKApply | _: AppliedType => val saved = available available = Set() try mapOver(t) @@ -453,7 +453,8 @@ class TypeApplications(val self: Type) extends AnyVal { case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => HKApply(self, args) case dealiased => - matchParams(dealiased, typParams, args) + if (Config.newScheme) ??? + else matchParams(dealiased, typParams, args) } } @@ -593,6 +594,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def withoutArgs(typeArgs: List[Type]): Type = self match { case HKApply(tycon, args) => tycon + case AppliedType(tycon, args) => tycon case _ => typeArgs match { case _ :: typeArgs1 => diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 09a476c8c9cb..bfeb5cd21189 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -342,6 +342,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // with `B[Y]`. To do the right thing, we need to instantiate `C` to the // common superclass of `A` and `B`. isSubType(tp1.join, tp2) + case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass => + isSubType(tp1.join, tp2) case _ => false } @@ -376,6 +378,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } private def thirdTry(tp1: Type, tp2: Type): Boolean = tp2 match { + case tp2 @ AppliedType(tycon2, args2) => + compareAppliedType2(tp1, tp2, tycon2, args2) case tp2: NamedType => thirdTryNamed(tp1, tp2) case tp2: TypeParamRef => @@ -569,6 +573,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { (sym1 eq NullClass) && isNullable(tp2) || (sym1 eq PhantomNothingClass) && tp1.topType == tp2.topType } + case tp1 @ AppliedType(tycon1, args1) => + compareAppliedType1(tp1, tycon1, args1, tp2) case tp1: SingletonType => /** if `tp2 == p.type` and `p: q.type` then try `tp1 <:< q.type` as a last effort.*/ def comparePaths = tp2 match { @@ -787,6 +793,172 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } + /** Subtype test for the hk application `tp2 = tycon2[args2]`. + */ + def compareAppliedType2(tp1: Type, tp2: AppliedType, tycon2: Type, args2: List[Type]): Boolean = { + val tparams = tycon2.typeParams + if (tparams.isEmpty) return false // can happen for ill-typed programs, e.g. neg/tcpoly_overloaded.scala + + /** True if `tp1` and `tp2` have compatible type constructors and their + * corresponding arguments are subtypes relative to their variance (see `isSubArgs`). + */ + def isMatchingApply(tp1: Type): Boolean = tp1 match { + case AppliedType(tycon1, args1) => + tycon1.dealias match { + case tycon1: TypeParamRef => + (tycon1 == tycon2 || + canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) && + isSubArgs(args1, args2, tparams) + case tycon1: TypeRef => + tycon2.dealias match { + case tycon2: TypeRef if tycon1.symbol == tycon2.symbol => + isSubType(tycon1.prefix, tycon2.prefix) && + isSubArgs(args1, args2, tparams) + case _ => + false + } + case tycon1: TypeVar => + isMatchingApply(tycon1.underlying) + case tycon1: AnnotatedType => + isMatchingApply(tycon1.underlying) + case _ => + false + } + case _ => + false + } + + /** `param2` can be instantiated to a type application prefix of the LHS + * or to a type application prefix of one of the LHS base class instances + * and the resulting type application is a supertype of `tp1`, + * or fallback to fourthTry. + */ + def canInstantiate(tycon2: TypeParamRef): Boolean = { + + /** Let + * + * `tparams_1, ..., tparams_k-1` be the type parameters of the rhs + * `tparams1_1, ..., tparams1_n-1` be the type parameters of the constructor of the lhs + * `args1_1, ..., args1_n-1` be the type arguments of the lhs + * `d = n - k` + * + * Returns `true` iff `d >= 0` and `tycon2` can be instantiated to + * + * [tparams1_d, ... tparams1_n-1] -> tycon1a[args_1, ..., args_d-1, tparams_d, ... tparams_n-1] + * + * such that the resulting type application is a supertype of `tp1`. + */ + def tyconOK(tycon1a: Type, args1: List[Type]) = { + var tycon1b = tycon1a + val tparams1a = tycon1a.typeParams + val lengthDiff = tparams1a.length - tparams.length + lengthDiff >= 0 && { + val tparams1 = tparams1a.drop(lengthDiff) + variancesConform(tparams1, tparams) && { + if (lengthDiff > 0) + tycon1b = HKTypeLambda(tparams1.map(_.paramName))( + tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), + tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ + tparams1.indices.toList.map(TypeParamRef(tl, _)))) + (ctx.mode.is(Mode.TypevarsMissContext) || + tryInstantiate(tycon2, tycon1b.ensureHK)) && + isSubType(tp1, tycon1b.appliedTo(args2)) + } + } + } + + tp1.widen match { + case tp1w @ HKApply(tycon1, args1) => + tyconOK(tycon1, args1) + case tp1w => + tp1w.typeSymbol.isClass && { + val classBounds = tycon2.classSymbols + def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match { + case bc :: bcs1 => + classBounds.exists(bc.derivesFrom) && + tyconOK(tp1w.baseTypeTycon(bc), tp1w.baseArgInfos(bc)) || + liftToBase(bcs1) + case _ => + false + } + liftToBase(tp1w.baseClasses) + } || + fourthTry(tp1, tp2) + } + } + + /** Fall back to comparing either with `fourthTry` or against the lower + * approximation of the rhs. + * @param tyconLo The type constructor's lower approximation. + */ + def fallback(tyconLo: Type) = + either(fourthTry(tp1, tp2), isSubType(tp1, tyconLo.applyIfParameterized(args2))) + + /** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`. + * Let `app2 = tp2` where the type constructor of `tp2` is replaced by + * `tycon2bounds.lo`. + * If both bounds are the same, continue with `tp1 <:< app2`. + * otherwise continue with either + * + * tp1 <:< tp2 using fourthTry (this might instantiate params in tp1) + * tp1 <:< app2 using isSubType (this might instantiate params in tp2) + */ + def compareLower(tycon2bounds: TypeBounds, tyconIsTypeRef: Boolean): Boolean = + if (tycon2bounds.lo eq tycon2bounds.hi) + isSubType(tp1, + if (tyconIsTypeRef) tp2.superType + else tycon2bounds.lo.applyIfParameterized(args2)) + else + fallback(tycon2bounds.lo) + + tycon2 match { + case param2: TypeParamRef => + isMatchingApply(tp1) || + canConstrain(param2) && canInstantiate(param2) || + compareLower(bounds(param2), tyconIsTypeRef = false) + case tycon2: TypeRef => + isMatchingApply(tp1) || { + tycon2.info match { + case tycon2: TypeBounds => + compareLower(tycon2, tyconIsTypeRef = true) + case tycon2: ClassInfo => + val base = tp1.baseType(tycon2.cls) + if (base.exists && base.ne(tp1)) isSubType(base, tp2) + else fourthTry(tp1, tp2) + case _ => + fourthTry(tp1, tp2) + } + } + case _: TypeVar | _: AnnotatedType => + isSubType(tp1, tp2.superType) + case tycon2: AppliedType => + fallback(tycon2.lowerBound) + case _ => + false + } + } + + /** Subtype test for the application `tp1 = tycon1[args1]`. + */ + def compareAppliedType1(tp1: AppliedType, tycon1: Type, args1: List[Type], tp2: Type): Boolean = + tycon1 match { + case param1: TypeParamRef => + def canInstantiate = tp2 match { + case AnyAppliedType(tycon2, args2) => + tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams) + case _ => + false + } + canConstrain(param1) && canInstantiate || + isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2) + case tycon1: TypeRef if tycon1.symbol.isClass => + false + case tycon1: TypeProxy => + isSubType(tp1.superType, tp2) + case _ => + false + } + /** Subtype test for corresponding arguments in `args1`, `args2` according to * variances in type parameters `tparams`. */ @@ -986,10 +1158,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** A type has been covered previously in subtype checking if it * is some combination of TypeRefs that point to classes, where the - * combiners are RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes. + * combiners are AppliedTypes, RefinedTypes, RecTypes, And/Or-Types or AnnotatedTypes. */ private def isCovered(tp: Type): Boolean = tp.dealias.stripTypeVar match { case tp: TypeRef => tp.symbol.isClass && tp.symbol != NothingClass && tp.symbol != NullClass + case tp: AppliedType => isCovered(tp.tycon) case tp: RefinedOrRecType => isCovered(tp.parent) case tp: AnnotatedType => isCovered(tp.underlying) case tp: AndOrType => isCovered(tp.tp1) && isCovered(tp.tp2) @@ -1203,6 +1376,38 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { final def lub(tps: List[Type]): Type = ((defn.NothingType: Type) /: tps)(lub(_,_, canConstrain = false)) + def lubArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo], canConstrain: Boolean = false): List[Type] = + tparams match { + case tparam :: tparamsRest => + val arg1 :: args1Rest = args1 + val arg2 :: args2Rest = args2 + val v = tparam.paramVariance + val lubArg = + if (v > 0) lub(arg1.hiBound, arg2.hiBound, canConstrain) + else if (v < 0) glb(arg1.loBound, arg2.loBound) + else TypeBounds(glb(arg1.loBound, arg2.loBound), + lub(arg1.hiBound, arg2.hiBound, canConstrain)) + lubArg :: lubArgs(args1Rest, args2Rest, tparamsRest, canConstrain) + case nil => + Nil + } + + def glbArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo]): List[Type] = + tparams match { + case tparam :: tparamsRest => + val arg1 :: args1Rest = args1 + val arg2 :: args2Rest = args2 + val v = tparam.paramVariance + val glbArg = + if (v > 0) glb(arg1.hiBound, arg2.hiBound) + else if (v < 0) lub(arg1.loBound, arg2.loBound) + else TypeBounds(lub(arg1.loBound, arg2.loBound), + glb(arg1.hiBound, arg2.hiBound)) + glbArg :: glbArgs(args1Rest, args2Rest, tparamsRest) + case nil => + Nil + } + private def recombineAndOr(tp: AndOrType, tp1: Type, tp2: Type) = if (!tp1.exists) tp2 else if (!tp2.exists) tp1 @@ -1342,6 +1547,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * @pre !(tp1 <: tp2) && !(tp2 <:< tp1) -- these cases were handled before */ private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match { + case tp1 @ AppliedType(tycon1, args1) => + tp2 match { + case AppliedType(tycon2, args2) if tycon1.typeSymbol == tycon2.typeSymbol => + (tycon1 & tycon2).appliedTo(glbArgs(args1, args2, tycon1.typeParams)) + case _ => + NoType + } // opportunistically merge same-named refinements // this does not change anything semantically (i.e. merging or not merging // gives =:= types), but it keeps the type smaller. @@ -1556,17 +1768,17 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) { override def copyIn(ctx: Context) = new ExplainingTypeComparer(ctx) - override def compareHkApply2(tp1: Type, tp2: HKApply, tycon2: Type, args2: List[Type]): Boolean = { + override def compareAppliedType2(tp1: Type, tp2: AppliedType, tycon2: Type, args2: List[Type]): Boolean = { def addendum = "" - traceIndented(i"compareHkApply2 $tp1, $tp2$addendum") { - super.compareHkApply2(tp1, tp2, tycon2, args2) + traceIndented(i"compareAppliedType2 $tp1, $tp2$addendum") { + super.compareAppliedType2(tp1, tp2, tycon2, args2) } } - override def compareHkApply1(tp1: HKApply, tycon1: Type, args1: List[Type], tp2: Type): Boolean = { + override def compareAppliedType1(tp1: AppliedType, tycon1: Type, args1: List[Type], tp2: Type): Boolean = { def addendum = "" - traceIndented(i"compareHkApply1 $tp1, $tp2$addendum") { - super.compareHkApply1(tp1, tycon1, args1, tp2) + traceIndented(i"compareAppliedType1 $tp1, $tp2$addendum") { + super.compareAppliedType1(tp1, tycon1, args1, tp2) } } diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 5e67e191e5cf..079e296ef495 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -381,6 +381,8 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else if (defn.isPhantomTerminalClass(sym)) PhantomErasure.erasedPhantomType else if (sym eq defn.PhantomClass) defn.ObjectType // To erase the definitions of Phantom.{assume, Any, Nothing} else eraseNormalClassRef(tp) + case tp: AppliedType => + apply(tp.superType) case tp: RefinedType => val parent = tp.parent if (parent isRef defn.ArrayClass) eraseArray(tp) @@ -509,8 +511,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean */ private def sigName(tp: Type)(implicit ctx: Context): TypeName = try { tp match { - case ErasedValueType(_, underlying) => - sigName(underlying) case tp: TypeRef => if (!tp.denot.exists) throw new MissingType(tp.prefix, tp.name) val sym = tp.symbol @@ -529,6 +529,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean sigName(PhantomErasure.erasedPhantomType) else normalizeClass(sym.asClass).fullName.asTypeName + case tp: AppliedType => + sigName(tp.superType) + case ErasedValueType(_, underlying) => + sigName(underlying) case defn.ArrayOf(elem) => sigName(this(tp)) case tp: HKApply => diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 9f172243f37d..b6fc6eee64a9 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -11,6 +11,7 @@ import NameKinds.DepParamName import Decorators._ import StdNames._ import Annotations._ +import annotation.tailrec import config.Config import util.{SimpleMap, Property} import collection.mutable @@ -48,6 +49,18 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } + @tailrec + def argForParam(pre: Type, cls: Symbol, pref: TypeParamRef, prefCls: ClassSymbol): Type = + if (cls.is(PackageClass)) pref + else { + val base = pre.baseType(cls) + if (cls eq prefCls) { + val AppliedType(_, args) = base + args(pref.paramNum) + } + else argForParam(base.normalizedPrefix, cls.owner.enclosingClass, pref, prefCls) + } + /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG // One `case ThisType` is specific to asSeenFrom, all other cases are inlined for performance tp match { @@ -56,6 +69,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object. else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix))) case tp: ThisType => toPrefix(pre, cls, tp.cls) + case tp: TypeParamRef => + tp.binder.resultType match { + case cinfo: ClassInfo => argForParam(pre, cls, tp, cinfo.cls) + case _ => tp + } case _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -92,7 +110,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object. val bounds = ctx.typeComparer.bounds(tp) if (bounds.lo.isRef(defn.NothingClass)) bounds.hi else bounds.lo } - else typerState.constraint.typeVarOfParam(tp) orElse tp + else { + val tvar = typerState.constraint.typeVarOfParam(tp) + if (tvar.exists) tvar else tp + } case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -142,14 +163,22 @@ trait TypeOps { this: Context => // TODO: Make standalone object. defn.ObjectClass :: Nil } - def mergeRefined(tp1: Type, tp2: Type): Type = { + def mergeRefinedOrApplied(tp1: Type, tp2: Type): Type = { def fail = throw new AssertionError(i"Failure to join alternatives $tp1 and $tp2") tp1 match { case tp1 @ RefinedType(parent1, name1, rinfo1) => tp2 match { case RefinedType(parent2, `name1`, rinfo2) => tp1.derivedRefinedType( - mergeRefined(parent1, parent2), name1, rinfo1 | rinfo2) + mergeRefinedOrApplied(parent1, parent2), name1, rinfo1 | rinfo2) + case _ => fail + } + case tp1 @ AppliedType(tycon1, args1) => + tp2 match { + case AppliedType(tycon2, args2) => + tp1.derivedAppliedType( + mergeRefinedOrApplied(tycon1, tycon2), + ctx.typeComparer.lubArgs(args1, args2, tycon1.typeParams)) case _ => fail } case tp1 @ TypeRef(pre1, name1) => @@ -187,7 +216,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. val base = if (tp1.typeParams.nonEmpty) tp.baseTypeTycon(cls) else tp.baseTypeWithArgs(cls) - base.mapReduceOr(identity)(mergeRefined) + base.mapReduceOr(identity)(mergeRefinedOrApplied) } doms.map(baseTp).reduceLeft(AndType.apply) } @@ -202,35 +231,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } - /** Not currently needed: - * - def liftToRec(f: (Type, Type) => Type)(tp1: Type, tp2: Type)(implicit ctx: Context) = { - def f2(tp1: Type, tp2: Type): Type = tp2 match { - case tp2: RecType => tp2.rebind(f(tp1, tp2.parent)) - case _ => f(tp1, tp2) - } - tp1 match { - case tp1: RecType => tp1.rebind(f2(tp1.parent, tp2)) - case _ => f2(tp1, tp2) - } - } - */ - - private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = { - val lazyInfo = new LazyType { // needed so we do not force `formal`. - def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { - denot setFlag formal.flags & RetainedTypeArgFlags - denot.info = info - } - } - val sym = ctx.newSymbol( - cls, formal.name, - formal.flagsUNSAFE & RetainedTypeArgFlags | BaseTypeArg | Override, - lazyInfo, - coord = cls.coord) - cls.enter(sym, decls) - } - /** If `tpe` is of the form `p.x` where `p` refers to a package * but `x` is not owned by a package, expand it to * @@ -253,6 +253,21 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } + private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = { + val lazyInfo = new LazyType { // needed so we do not force `formal`. + def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { + denot setFlag formal.flags & RetainedTypeArgFlags + denot.info = info + } + } + val sym = ctx.newSymbol( + cls, formal.name, + formal.flagsUNSAFE & RetainedTypeArgFlags | BaseTypeArg | Override, + lazyInfo, + coord = cls.coord) + cls.enter(sym, decls) + } + /** Normalize a list of parent types of class `cls` that may contain refinements * to a list of typerefs referring to classes, by converting all refinements to member * definitions in scope `decls`. Can add members to `decls` as a side-effect. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 17b45e9e4a29..ca8ef59b92f0 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1413,7 +1413,7 @@ object Types { /** The closest supertype of this type. This is the same as `underlying`, * except that * - instead of a TyperBounds type it returns its upper bound, and - * - for HKApplys it returns the upper bound of the constructor re-applied to the arguments. + * - for applied types it returns the upper bound of the constructor re-applied to the arguments. */ def superType(implicit ctx: Context): Type = underlying match { case TypeBounds(_, hi) => hi @@ -3758,6 +3758,8 @@ object Types { } if ((tp.cls is Trait) || zeroParams(tp.cls.primaryConstructor.info)) tp // !!! needs to be adapted once traits have parameters else NoType + case tp: AppliedType => + zeroParamClass(tp.superType) case tp: TypeRef => zeroParamClass(tp.underlying) case tp: RefinedType => @@ -3835,6 +3837,8 @@ object Types { tp.derivedTypeBounds(lo, hi) protected def derivedSuperType(tp: SuperType, thistp: Type, supertp: Type): Type = tp.derivedSuperType(thistp, supertp) + protected def derivedAppliedType(tp: AppliedType, tycon: Type, args: List[Type]): Type = + tp.derivedAppliedType(tycon, args) protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = tp.derivedAppliedType(tycon, args) protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type): Type = @@ -3873,6 +3877,16 @@ object Types { | _: BoundType | NoPrefix => tp + case tp: AppliedType => // @!!! use atVariance + def mapArg(arg: Type, tparam: ParamInfo): Type = { + val saved = variance + variance *= tparam.paramVariance + try this(arg) + finally variance = saved + } + derivedAppliedType(tp, this(tp.tycon), + tp.args.zipWithConserve(tp.typeParams)(mapArg)) + case tp: RefinedType => derivedRefinedType(tp, this(tp.parent), this(tp.refinedInfo)) @@ -4119,7 +4133,7 @@ object Types { if (isRange(thistp) || isRange(supertp)) range(thistp.bottomType, thistp.topType) else tp.derivedSuperType(thistp, supertp) - override protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = + override protected def derivedAppliedType(tp: AppliedType, tycon: Type, args: List[Type]): Type = tycon match { case Range(tyconLo, tyconHi) => range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args)) @@ -4160,6 +4174,46 @@ object Types { else tp.derivedAppliedType(tycon, args) } + override protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = + tycon match { + case Range(tyconLo, tyconHi) => + range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args)) + case _ => + if (args.exists(isRange)) { + if (variance > 0) tp.derivedAppliedType(tycon, args.map(rangeToBounds)) + else { + val loBuf, hiBuf = new mutable.ListBuffer[Type] + // Given `C[A1, ..., An]` where sone A's are ranges, try to find + // non-range arguments L1, ..., Ln and H1, ..., Hn such that + // C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of + // ranges that appear in as co- or contravariant arguments. + // Fail for non-variant argument ranges. + // If successful, the L-arguments are in loBut, the H-arguments in hiBuf. + // @return operation succeeded for all arguments. + def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match { + case Range(lo, hi) :: args1 => + val v = tparams.head.paramVariance + if (v == 0) false + else { + if (v > 0) { loBuf += lo; hiBuf += hi } + else { loBuf += hi; hiBuf += lo } + distributeArgs(args1, tparams.tail) + } + case arg :: args1 => + loBuf += arg; hiBuf += arg + distributeArgs(args1, tparams.tail) + case nil => + true + } + if (distributeArgs(args, tp.typeParams)) + range(tp.derivedAppliedType(tycon, loBuf.toList), + tp.derivedAppliedType(tycon, hiBuf.toList)) + else range(tp.bottomType, tp.topType) + // TODO: can we give a better bound than `topType`? + } + } + else tp.derivedAppliedType(tycon, args) + } override protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type) = if (isRange(tp1) || isRange(tp2)) if (tp.isAnd) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2)) @@ -4236,6 +4290,23 @@ object Types { | _: BoundType | NoPrefix => x + case tp @ AppliedType(tycon, args) => + @tailrec def foldArgs(x: T, tparams: List[ParamInfo], args: List[Type]): T = + if (args.isEmpty) { + assert(tparams.isEmpty) + x + } + else { // @@!!! use atVariance + val tparam = tparams.head + val saved = variance + variance *= tparam.paramVariance + val acc = + try this(x, args.head) + finally variance = saved + foldArgs(acc, tparams.tail, args.tail) + } + foldArgs(this(x, tycon), tp.typeParams, args) + case tp: RefinedType => this(this(x, tp.parent), tp.refinedInfo) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 4c73115cac50..585085f1d9e5 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -329,11 +329,11 @@ class ClassfileParser( case '*' => TypeBounds.empty } if (formals != null) - tp1 = RefinedType(tp1, formals.head.name, bounds) + tp1 = RefinedType(tp1, formals.head.name, bounds) // @!!! case _ => val info = sig2type(tparams, skiptvs) if (formals != null) - tp1 = RefinedType(tp1, formals.head.name, TypeAlias(info)) + tp1 = RefinedType(tp1, formals.head.name, TypeAlias(info)) // @!!! } if (formals != null) formals = formals.tail diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index c36ce1dc14bb..f9ce4f07b9ab 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -670,6 +670,14 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas } if (tycon1 ne tycon) elim(tycon1.appliedTo(args)) else tp.derivedAppliedType(tycon, args.map(mapArg)) + case tp @ AppliedType(tycon, args) => + val tycon1 = tycon.safeDealias + def mapArg(arg: Type) = arg match { + case arg: TypeRef if isBound(arg) => arg.symbol.info + case _ => arg + } + if (tycon1 ne tycon) elim(tycon1.appliedTo(args)) + else tp.derivedAppliedType(tycon, args.map(mapArg)) case _ => tp } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 3f3bd6e852e2..8b716c5ff53d 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -62,6 +62,8 @@ class PlainPrinter(_ctx: Context) extends Printer { homogenize(tp.info) case tp: LazyRef => homogenize(tp.ref) + case AppliedType(tycon, args) => + tycon.dealias.appliedTo(args) case HKApply(tycon, args) => tycon.dealias.appliedTo(args) case _ => @@ -199,6 +201,8 @@ class PlainPrinter(_ctx: Context) extends Printer { ParamRefNameString(tp) ~ ".type" case AnnotatedType(tpe, annot) => toTextLocal(tpe) ~ " " ~ toText(annot) + case AppliedType(tycon, args) => + toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" case HKApply(tycon, args) => toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" case tp: TypeVar => diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 0b7d063cdc9d..1451fedc2d8f 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -429,6 +429,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { /* Erase a type binding according to erasure semantics in pattern matching */ def erase(tp: Type): Type = { def doErase(tp: Type): Type = tp match { + case tp: AppliedType => erase(tp.superType) case tp: HKApply => erase(tp.superType) case tp: RefinedType => erase(tp.parent) case _ => tp @@ -552,9 +553,13 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { * * If `tp1` is `path1.A`, `tp2` is `path2.B`, and `path1` is subtype of * `path2`, then return `path1.B`. + * + * (MO) I don't really understand what this does. Let's try to find a precise + * definition! */ def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match { case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2)) + case (tp1: AppliedType, _) => refine(tp1.superType, tp2) case (tp1: HKApply, _) => refine(tp1.superType, tp2) case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) => if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2 diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 4ebef4900d7d..31585337b073 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -83,7 +83,16 @@ object Checking { HKTypeLambda.fromParams(tparams, bound).appliedTo(args) checkBounds(orderedArgs, bounds, instantiate) - def checkWildcardHKApply(tp: Type, pos: Position): Unit = tp match { + def checkWildcardApply(tp: Type, pos: Position): Unit = tp match { + case tp @ AppliedType(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) => + tycon match { + case tycon: TypeLambda => + ctx.errorOrMigrationWarning( + ex"unreducible application of higher-kinded type $tycon to wildcard arguments", + pos) + case _ => + checkWildcardApply(tp.superType, pos) + } case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) => tycon match { case tycon: TypeLambda => @@ -91,13 +100,13 @@ object Checking { ex"unreducible application of higher-kinded type $tycon to wildcard arguments", pos) case _ => - checkWildcardHKApply(tp.superType, pos) + checkWildcardApply(tp.superType, pos) } case _ => } - def checkValidIfHKApply(implicit ctx: Context): Unit = - checkWildcardHKApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos) - checkValidIfHKApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) + def checkValidIfApply(implicit ctx: Context): Unit = + checkWildcardApply(tycon.tpe.appliedTo(args.map(_.tpe)), tree.pos) + checkValidIfApply(ctx.addMode(Mode.AllowLambdaWildcardApply)) } /** Check that kind of `arg` has the same outline as the kind of paramBounds. @@ -213,6 +222,8 @@ object Checking { case tp: TermRef => this(tp.info) mapOver(tp) + case tp @ AppliedType(tycon, args) => + tp.derivedAppliedType(this(tycon), args.map(this(_, nestedCycleOK, nestedCycleOK))) case tp @ RefinedType(parent, name, rinfo) => tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK)) case tp: RecType => @@ -234,7 +245,7 @@ object Checking { case SuperType(thistp, _) => isInteresting(thistp) case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2) case OrType(tp1, tp2) => isInteresting(tp1) && isInteresting(tp2) - case _: RefinedOrRecType | _: HKApply => true + case _: RefinedOrRecType | _: HKApply | _: AppliedType => true case _ => false } if (isInteresting(pre)) { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 10cfcf87cf15..46452a065a19 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -385,6 +385,13 @@ trait ImplicitRunInfo { self: RunInfo => (lead /: tp.classSymbols)(joinClass) case tp: TypeVar => apply(tp.underlying) + case tp: AppliedType => + def applyArg(arg: Type) = arg match { + case TypeBounds(lo, hi) => AndType.make(lo, hi) + case _: WildcardType => defn.AnyType + case _ => arg + } + (apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg))) case tp: HKApply => def applyArg(arg: Type) = arg match { case TypeBounds(lo, hi) => AndType.make(lo, hi) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 4906a26966a2..48dbf43af885 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -474,6 +474,11 @@ object ProtoTypes { case tp: NamedType => // default case, inlined for speed if (tp.symbol.isStatic) tp else tp.derivedSelect(wildApprox(tp.prefix, theMap, seen)) + case tp @ AppliedType(tycon, args) => + wildApprox(tycon, theMap, seen) match { + case _: WildcardType => WildcardType // this ensures we get a * type + case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen))) + } case tp: RefinedType => // default case, inlined for speed tp.derivedRefinedType( wildApprox(tp.parent, theMap, seen), diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index aeeef02755c5..20fadccc3d7d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -83,6 +83,17 @@ object Variances { flip(varianceInTypes(tp.paramInfos)(tparam)) & varianceInType(tp.resultType)(tparam) case ExprType(restpe) => varianceInType(restpe)(tparam) + case tp @ AppliedType(tycon, args) => + def varianceInArgs(v: Variance, args: List[Type], tparams: List[ParamInfo]): Variance = + args match { + case arg :: args1 => + varianceInArgs( + v & compose(varianceInType(arg)(tparam), tparams.head.paramVariance), + args1, tparams.tail) + case nil => + v + } + varianceInArgs(varianceInType(tycon)(tparam), args, tycon.typeParams) case tp @ HKApply(tycon, args) => def varianceInArgs(v: Variance, args: List[Type], tparams: List[ParamInfo]): Variance = args match { diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 563a20938372..705a06580a89 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -176,7 +176,7 @@ object factories { paramLists(annot.tpe) case (_: TypeParamRef | _: RefinedType | _: TypeRef | _: ThisType | - _: ExprType | _: OrType | _: AndType | _: HKApply | + _: ExprType | _: OrType | _: AndType | _: HKApply | _: AppliedType | _: TermRef | _: ConstantType) => Nil // return types should not be in the paramlist } From 6a63549b2399032a340982a12f1c1f62fb8dbff2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 26 Jul 2017 13:24:11 +0200 Subject: [PATCH 005/146] Introduce TypeArgRef Also, change asSeenFrom to use it for arguments --- .../src/dotty/tools/dotc/ast/Desugar.scala | 5 +- .../tools/dotc/core/ConstraintHandling.scala | 12 +- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 5 +- .../src/dotty/tools/dotc/core/Flags.scala | 4 +- .../dotty/tools/dotc/core/Substituters.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 39 ++++--- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../tools/dotc/core/TypeApplications.scala | 64 ++++------ .../dotty/tools/dotc/core/TypeComparer.scala | 66 ++++++----- .../dotty/tools/dotc/core/TypeErasure.scala | 24 ++-- .../src/dotty/tools/dotc/core/TypeOps.scala | 60 +++++----- .../src/dotty/tools/dotc/core/Types.scala | 110 +++++++++++++----- .../dotc/core/classfile/ClassfileParser.scala | 35 +++--- .../tools/dotc/core/tasty/TastyFormat.scala | 5 +- .../tools/dotc/core/tasty/TreePickler.scala | 5 +- .../tools/dotc/core/tasty/TreeUnpickler.scala | 8 +- .../tools/dotc/printing/PlainPrinter.scala | 7 +- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../tools/dotc/transform/CheckReentrant.scala | 4 +- .../tools/dotc/transform/PostTyper.scala | 2 +- .../localopt/InlineCaseIntrinsics.scala | 3 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 33 ++++-- .../dotty/tools/dotc/typer/Implicits.scala | 10 +- .../dotty/tools/dotc/typer/RefChecks.scala | 4 +- .../src/dotty/tools/dotc/typer/Typer.scala | 15 +-- .../tools/dottydoc/model/factories.scala | 2 +- 28 files changed, 317 insertions(+), 215 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 4b3ea0df7e75..3b103071cdc1 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -245,7 +245,7 @@ object desugar { * class C { type v C$T; type v T = C$T } */ def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { - if (tdef.mods is PrivateLocalParam) { + if (tdef.mods.is(PrivateLocalParam) && !dotty.tools.dotc.config.Config.newScheme) { val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) .withMods(tdef.mods &~ PrivateLocal) val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) @@ -1132,7 +1132,8 @@ object desugar { */ def refinedTypeToClass(parent: tpd.Tree, refinements: List[Tree])(implicit ctx: Context): TypeDef = { def stripToCore(tp: Type): List[Type] = tp match { - case tp: RefinedType if tp.argInfos.nonEmpty => tp :: Nil // parameterized class type + case tp: AppliedType => tp :: Nil + case tp: RefinedType if !config.Config.newScheme && tp.argInfos.nonEmpty => tp :: Nil // parameterized class type case tp: TypeRef if tp.symbol.isClass => tp :: Nil // monomorphic class type case tp: TypeProxy => stripToCore(tp.underlying) case AndType(tp1, tp2) => stripToCore(tp1) ::: stripToCore(tp2) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 81ee865aa96c..b11a2caaf0ff 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -6,7 +6,7 @@ import Types._, Contexts._, Symbols._ import Decorators._ import config.Config import config.Printers.{constr, typr} -import TypeApplications.EtaExpansion +import TypeApplications.{EtaExpansion, TypeParamInfo} import collection.mutable /** Methods for adding constraints and solving them. @@ -194,9 +194,17 @@ trait ConstraintHandling { final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = { val avoidParam = new TypeMap { override def stopAtStatic = true + def avoidInArg(arg: Type, formal: TypeParamInfo): Type = + if (param.occursIn(arg)) TypeBounds.empty else arg def apply(tp: Type) = mapOver { tp match { - case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent + case tp @ AppliedType(tycon, args) => + tp.derivedAppliedType(tycon, + args.zipWithConserve(tycon.typeParams)(avoidInArg)) + case tp: RefinedType if param occursIn tp.refinedInfo => + assert(fromBelow || variance <= 0, + "unsound approximation of $param with bounds ${constraint.fullUpperBound(param)}") + tp.parent case tp: WildcardType => val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds // Try to instantiate the wildcard to a type that is known to conform to it. diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 7b687afeb9f2..fb60245efa37 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -610,7 +610,7 @@ object Contexts { } /** A table for hash consing unique refined types */ - private[dotc] val uniqueRefinedTypes = new RefinedUniques + private[dotc] val uniqueRefinedTypes = new RefinedUniques // @!!! replace with uniqueAppliedTypes /** A table for hash consing unique named types */ private[core] val uniqueNamedTypes = new NamedTypeUniques diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index ce2ce247060c..c3ee13131fd6 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -82,7 +82,7 @@ class Definitions { if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef) else tpe val parents = parentConstrs.toList map instantiate - val parentRefs: List[TypeRef] = ctx.normalizeToClassRefs(parents, cls, paramDecls) + val parentRefs = ctx.normalizeToClassRefs(parents, cls, paramDecls) denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls) } } @@ -719,7 +719,8 @@ class Definitions { if (ctx.erasedTypes) JavaArrayType(elem) else ArrayType.appliedTo(elem :: Nil) def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match { - case at: RefinedType if (at isRef ArrayType.symbol) && at.argInfos.length == 1 => Some(at.argInfos.head) + case AppliedType(at, arg :: Nil) if at isRef ArrayType.symbol => Some(arg) + case at: RefinedType if (at isRef ArrayType.symbol) && at.argInfos.length == 1 => Some(at.argInfos.head) // @!!! case _ => None } } diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 59135bf21441..6ec87012cdc9 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -250,7 +250,7 @@ object Flags { */ final val ParamAccessor = commonFlag(14, "") final val TermParamAccessor = ParamAccessor.toTermFlags - final val TypeParamAccessor = ParamAccessor.toTypeFlags + final val TypeParamAccessor = ParamAccessor.toTypeFlags // @!!! /** A value or class implementing a module */ final val Module = commonFlag(15, "module") @@ -306,7 +306,7 @@ object Flags { /** A binding for a type parameter of a base class or trait. */ - final val BaseTypeArg = typeFlag(25, "") + final val BaseTypeArg = typeFlag(25, "") // @!!! final val CaseAccessorOrBaseTypeArg = CaseAccessor.toCommonFlags diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index d565ec2293aa..fabcd5712d26 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -16,7 +16,7 @@ trait Substituters { this: Context => else tp.derivedSelect(subst(tp.prefix, from, to, theMap)) case _: ThisType | NoPrefix => tp - case tp: RefinedType => + case tp: RefinedType => // @!!! remove tp.derivedRefinedType(subst(tp.parent, from, to, theMap), tp.refinedName, subst(tp.refinedInfo, from, to, theMap)) case tp: TypeAlias => tp.derivedTypeAlias(subst(tp.alias, from, to, theMap)) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 64d45c30b696..d95f44e6156d 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -46,8 +46,8 @@ trait SymDenotations { this: Context => else { val initial = denot.initial val firstPhaseId = initial.validFor.firstPhaseId.max(ctx.typerPhase.id) - if ((initial ne denot) || ctx.phaseId != firstPhaseId) { - ctx.withPhase(firstPhaseId).stillValidInOwner(initial) || + if ((initial ne denot) || ctx.phaseId != firstPhaseId) { + ctx.withPhase(firstPhaseId).stillValidInOwner(initial) || // Workaround #1895: A symbol might not be entered into an owner // until the second phase where it exists (denot.validFor.containsPhaseId(firstPhaseId + 1)) && @@ -1223,7 +1223,7 @@ object SymDenotations { info2 match { case info2: ClassInfo => info1 match { - case info1: ClassInfo => info1.classParents ne info2.classParents + case info1: ClassInfo => info1.classParentsNEW ne info2.classParentsNEW case _ => completersMatter } case _ => completersMatter @@ -1369,13 +1369,24 @@ object SymDenotations { } /** The denotations of all parents in this class. */ - def classParents(implicit ctx: Context): List[TypeRef] = info match { - case classInfo: ClassInfo => classInfo.classParents + def classParentRefs(implicit ctx: Context): List[TypeRef] = info match { + case classInfo: ClassInfo => classInfo.parentRefs + case _ => Nil + } + + /** The denotations of all parents in this class. */ + def classParentsWithArgs(implicit ctx: Context): List[Type] = info match { + case classInfo: ClassInfo => classInfo.parentsWithArgs + case _ => Nil + } + + def classParentsNEW(implicit ctx: Context): List[Type] = info match { + case classInfo: ClassInfo => classInfo.parentsNEW case _ => Nil } /** The symbol of the superclass, NoSymbol if no superclass exists */ - def superClass(implicit ctx: Context): Symbol = classParents match { + def superClass(implicit ctx: Context): Symbol = classParentsNEW match { case parent :: _ => val cls = parent.classSymbol if (cls is Trait) NoSymbol else cls @@ -1441,10 +1452,10 @@ object SymDenotations { def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = { def emptyParentsExpected = is(Package) || (symbol == defn.AnyClass) || ctx.erasedTypes && (symbol == defn.ObjectClass) - if (classParents.isEmpty && !emptyParentsExpected) + if (classParentsNEW.isEmpty && !emptyParentsExpected) onBehalf.signalProvisional() val builder = new BaseDataBuilder - for (p <- classParents) builder.addAll(p.symbol.asClass.baseClasses) + for (p <- classParentsNEW) builder.addAll(p.typeSymbol.asClass.baseClasses) (classSymbol :: builder.baseClasses, builder.baseClassSet) } @@ -1570,10 +1581,10 @@ object SymDenotations { val ownDenots = info.decls.denotsNamed(name, selectNonPrivate) if (debugTrace) // DEBUG println(s"$this.member($name), ownDenots = $ownDenots") - def collect(denots: PreDenotation, parents: List[TypeRef]): PreDenotation = parents match { + def collect(denots: PreDenotation, parents: List[Type]): PreDenotation = parents match { case p :: ps => val denots1 = collect(denots, ps) - p.symbol.denot match { + p.typeSymbol.denot match { case parentd: ClassDenotation => denots1 union parentd.nonPrivateMembersNamed(name) @@ -1585,7 +1596,7 @@ object SymDenotations { denots } if (name.isConstructorName) ownDenots - else collect(ownDenots, classParents) + else collect(ownDenots, classParentsNEW) } override final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = { @@ -1632,7 +1643,7 @@ object SymDenotations { tp else subcls.denot match { case cdenot: ClassDenotation => - if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parentsNEW) // !!! change to parents + if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parentsNEW) else NoType case _ => baseTypeOf(tp.superType) @@ -1687,8 +1698,8 @@ object SymDenotations { def computeMemberNames(keepOnly: NameFilter)(implicit onBehalf: MemberNames, ctx: Context): Set[Name] = { var names = Set[Name]() def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name - for (p <- classParents) - for (name <- p.symbol.asClass.memberNames(keepOnly)) + for (p <- classParentsNEW) + for (name <- p.typeSymbol.asClass.memberNames(keepOnly)) maybeAdd(name) val ownSyms = if (keepOnly eq implicitFilter) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 8c6a7148c4d2..d9577f05e842 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -123,7 +123,7 @@ trait Symbols { this: Context => def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol val decls = newScope - val parentRefs: List[TypeRef] = normalizeToClassRefs(parentTypes, cls, decls) + val parentRefs = normalizeToClassRefs(parentTypes, cls, decls) denot.info = ClassInfo(owner.thisType, cls, parentRefs, decls) } } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 199b63e24880..b1807f9e2a4c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -25,23 +25,11 @@ object TypeApplications { type TypeParamInfo = ParamInfo.Of[TypeName] /** Assert type is not a TypeBounds instance and return it unchanged */ - val noBounds = (tp: Type) => tp match { + def noBounds(tp: Type) = tp match { case tp: TypeBounds => throw new AssertionError("no TypeBounds allowed") case _ => tp } - /** If `tp` is a TypeBounds instance return its lower bound else return `tp` */ - val boundsToLo = (tp: Type) => tp match { - case tp: TypeBounds => tp.lo - case _ => tp - } - - /** If `tp` is a TypeBounds instance return its upper bound else return `tp` */ - val boundsToHi = (tp: Type) => tp match { - case tp: TypeBounds => tp.hi - case _ => tp - } - /** Does variance `v1` conform to variance `v2`? * This is the case if the variances are the same or `sym` is nonvariant. */ @@ -226,7 +214,7 @@ class TypeApplications(val self: Type) extends AnyVal { else if (!tsym.isCompleting) tsym.info.typeParams else Nil case self: RefinedType => - self.parent.typeParams.filterNot(_.paramName == self.refinedName) + self.parent.typeParams.filterNot(_.paramName == self.refinedName) // @!!! case self: RecType => self.parent.typeParams case _: SingletonType => @@ -259,6 +247,7 @@ class TypeApplications(val self: Type) extends AnyVal { def hkResult(implicit ctx: Context): Type = self.dealias match { case self: TypeRef => self.info.hkResult case self: RefinedType => NoType + case self: AppliedType => NoType case self: HKTypeLambda => self.resultType case self: SingletonType => NoType case self: TypeVar => @@ -401,6 +390,12 @@ class TypeApplications(val self: Type) extends AnyVal { } case nil => t } + def normalizeWildcardArg(arg: Type, tparam: TypeParamInfo): Type = arg match { + case TypeBounds(lo, hi) => + val v = tparam.paramVariance + if (v > 0) hi else if (v < 0) lo else arg + case _ => arg + } val stripped = self.stripTypeVar val dealiased = stripped.safeDealias if (args.isEmpty || ctx.erasedTypes) self @@ -453,8 +448,10 @@ class TypeApplications(val self: Type) extends AnyVal { case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => HKApply(self, args) case dealiased => - if (Config.newScheme) ??? - else matchParams(dealiased, typParams, args) + if (Config.newScheme) + AppliedType(self, args.zipWithConserve(typParams)(normalizeWildcardArg)) + else + matchParams(dealiased, typParams, args) } } @@ -488,10 +485,12 @@ class TypeApplications(val self: Type) extends AnyVal { } /** The type arguments of this type's base type instance wrt. `base`. - * Existential types in arguments are returned as TypeBounds instances. + * Wildcard types in arguments are returned as TypeBounds instances. */ final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = - if (self derivesFrom base) + if (Config.newScheme) + self.baseType(base).argInfos + else if (self derivesFrom base) self.dealias match { case self: TypeRef if !self.symbol.isClass => self.superType.baseArgInfos(base) case self: HKApply => self.superType.baseArgInfos(base) @@ -500,30 +499,14 @@ class TypeApplications(val self: Type) extends AnyVal { else Nil - /** The type arguments of this type's base type instance wrt.`base`. - * Existential types in arguments are disallowed. - */ - final def baseArgTypes(base: Symbol)(implicit ctx: Context): List[Type] = - baseArgInfos(base) mapConserve noBounds - - /** The type arguments of this type's base type instance wrt.`base`. - * Existential types in arguments are approximated by their lower bound. - */ - final def baseArgTypesLo(base: Symbol)(implicit ctx: Context): List[Type] = - baseArgInfos(base) mapConserve boundsToLo - - /** The type arguments of this type's base type instance wrt.`base`. - * Existential types in arguments are approximated by their upper bound. - */ - final def baseArgTypesHi(base: Symbol)(implicit ctx: Context): List[Type] = - baseArgInfos(base) mapConserve boundsToHi - /** The base type including all type arguments and applicable refinements * of this type. Refinements are applicable if they refine a member of * the parent type which furthermore is not a name-mangled type parameter. * 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) { + final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = + if (Config.newScheme) self.baseType(base) + else ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { def default = self.baseTypeTycon(base).appliedTo(baseArgInfos(base)) def isExpandedTypeParam(sym: Symbol) = sym.is(TypeParam) && sym.name.is(ExpandedName) self match { @@ -557,6 +540,7 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => if (self.derivesFrom(from)) if (ctx.erasedTypes) to.typeRef + else if (Config.newScheme) to.typeRef.appliedTo(self.baseType(from).argInfos) else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) else self } @@ -584,10 +568,10 @@ class TypeApplications(val self: Type) extends AnyVal { def argTypes(implicit ctx: Context) = argInfos mapConserve noBounds /** Argument types where existential types in arguments are approximated by their lower bound */ - def argTypesLo(implicit ctx: Context) = argInfos mapConserve boundsToLo + def argTypesLo(implicit ctx: Context) = argInfos.mapConserve(_.loBound) /** Argument types where existential types in arguments are approximated by their upper bound */ - def argTypesHi(implicit ctx: Context) = argInfos mapConserve boundsToHi + def argTypesHi(implicit ctx: Context) = argInfos.mapConserve(_.hiBound) /** The core type without any type arguments. * @param `typeArgs` must be the type arguments of this type. @@ -598,7 +582,7 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => typeArgs match { case _ :: typeArgs1 => - val RefinedType(tycon, _, _) = self + val RefinedType(tycon, _, _) = self // @!!! tycon.withoutArgs(typeArgs1) case nil => self diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index bfeb5cd21189..d29c4d01b027 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -525,6 +525,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case _ => isSubType(tp1.widenExpr, restpe2) } compareExpr + case tp2: TypeArgRef => + isSubType(tp1, tp2.underlying.loBound) || fourthTry(tp1, tp2) case tp2 @ TypeBounds(lo2, hi2) => def compareTypeBounds = tp1 match { case tp1 @ TypeBounds(lo1, hi1) => @@ -594,6 +596,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { isNewSubType(tp1.parent, tp2) case tp1: RecType => isNewSubType(tp1.parent, tp2) + case tp1: TypeArgRef => + isSubType(tp1.underlying.hiBound, tp2) case tp1 @ HKApply(tycon1, args1) => compareHkApply1(tp1, tycon1, args1, tp2) case tp1: HKTypeLambda => @@ -848,35 +852,36 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * * such that the resulting type application is a supertype of `tp1`. */ - def tyconOK(tycon1a: Type, args1: List[Type]) = { - var tycon1b = tycon1a - val tparams1a = tycon1a.typeParams - val lengthDiff = tparams1a.length - tparams.length - lengthDiff >= 0 && { - val tparams1 = tparams1a.drop(lengthDiff) - variancesConform(tparams1, tparams) && { - if (lengthDiff > 0) - tycon1b = HKTypeLambda(tparams1.map(_.paramName))( - tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), - tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ - tparams1.indices.toList.map(TypeParamRef(tl, _)))) - (ctx.mode.is(Mode.TypevarsMissContext) || - tryInstantiate(tycon2, tycon1b.ensureHK)) && - isSubType(tp1, tycon1b.appliedTo(args2)) + def appOK(tp1base: Type) = tp1base match { + case tp1base: AppliedType => + var tycon1 = tp1base.tycon + var args1 = tp1base.args + val tparams1all = tycon1.typeParams + val lengthDiff = tparams1all.length - tparams.length + lengthDiff >= 0 && { + val tparams1 = tparams1all.drop(lengthDiff) + variancesConform(tparams1, tparams) && { + if (lengthDiff > 0) + tycon1 = HKTypeLambda(tparams1.map(_.paramName))( + tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), + tl => tp1base.tycon.appliedTo(args1.take(lengthDiff) ++ + tparams1.indices.toList.map(TypeParamRef(tl, _)))) + (ctx.mode.is(Mode.TypevarsMissContext) || + tryInstantiate(tycon2, tycon1.ensureHK)) && + isSubType(tp1, tycon1.appliedTo(args2)) + } } - } + case _ => false } tp1.widen match { - case tp1w @ HKApply(tycon1, args1) => - tyconOK(tycon1, args1) + case tp1w: AppliedType => appOK(tp1w) case tp1w => tp1w.typeSymbol.isClass && { val classBounds = tycon2.classSymbols def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match { case bc :: bcs1 => - classBounds.exists(bc.derivesFrom) && - tyconOK(tp1w.baseTypeTycon(bc), tp1w.baseArgInfos(bc)) || + classBounds.exists(bc.derivesFrom) && appOK(tp1w.baseType(bc)) || liftToBase(bcs1) case _ => false @@ -985,12 +990,20 @@ 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.baseTypeTycon(bc) - (classBounds.exists(bc.derivesFrom) && - variancesConform(baseRef.typeParams, tparams) && - p(baseRef.appliedTo(tp1.baseArgInfos(bc))) - || - recur(bcs1)) + if (Config.newScheme) + (classBounds.exists(bc.derivesFrom) && + variancesConform(bc.typeParams, tparams) && + p(tp1.baseType(bc)) + || + recur(bcs1)) + else { + val baseRef = tp1.baseTypeTycon(bc) + (classBounds.exists(bc.derivesFrom) && + variancesConform(baseRef.typeParams, tparams) && + p(baseRef.appliedTo(tp1.baseArgInfos(bc))) + || + recur(bcs1)) + } case nil => false } @@ -1557,6 +1570,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // opportunistically merge same-named refinements // this does not change anything semantically (i.e. merging or not merging // gives =:= types), but it keeps the type smaller. + // @!!! still needed? case tp1: RefinedType => tp2 match { case tp2: RefinedType if tp1.refinedName == tp2.refinedName => diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 079e296ef495..8969fa8b44e1 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -382,10 +382,11 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else if (sym eq defn.PhantomClass) defn.ObjectType // To erase the definitions of Phantom.{assume, Any, Nothing} else eraseNormalClassRef(tp) case tp: AppliedType => - apply(tp.superType) + if (tp.tycon.isRef(defn.ArrayClass)) eraseArray(tp) + else apply(tp.superType) case tp: RefinedType => val parent = tp.parent - if (parent isRef defn.ArrayClass) eraseArray(tp) + if (parent isRef defn.ArrayClass) eraseArray(tp) // @!!! else this(parent) case _: TermRef | _: ThisType => this(tp.widen) @@ -414,13 +415,12 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean } case tp: PolyType => this(tp.resultType) - case tp @ ClassInfo(pre, cls, classParents, decls, _) => + case tp @ ClassInfo(pre, cls, parents, decls, _) => if (cls is Package) tp else { - def eraseTypeRef(p: TypeRef) = this(p).asInstanceOf[TypeRef] - val parents: List[TypeRef] = + val erasedParents: List[Type] = if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil - else classParents.mapConserve(eraseTypeRef) match { + else parents.mapConserve(apply) match { case tr :: trs1 => assert(!tr.classSymbol.is(Trait), cls) val tr1 = if (cls is Trait) defn.ObjectType else tr @@ -428,7 +428,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case nil => nil } val erasedDecls = decls.filteredScope(sym => !sym.isType || sym.isClass) - tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType)) + tp.derivedClassInfo(NoPrefix, erasedParents, erasedDecls, erasedRef(tp.selfType)) // can't replace selftype by NoType because this would lose the sourceModule link } case NoType | NoPrefix | _: ErrorType | JavaArrayType(_) => @@ -439,7 +439,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean this(tp.underlying) } - private def eraseArray(tp: RefinedType)(implicit ctx: Context) = { + private def eraseArray(tp: Type)(implicit ctx: Context) = { val defn.ArrayOf(elemtp) = tp def arrayErasure(tpToErase: Type) = erasureFn(isJava, semiEraseVCs = false, isConstructor, wildcardOK)(tpToErase) @@ -490,8 +490,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean // constructor method should not be semi-erased. else if (isConstructor && isDerivedValueClass(sym)) eraseNormalClassRef(tp) else this(tp) - case RefinedType(parent, _, _) if !(parent isRef defn.ArrayClass) => + case RefinedType(parent, _, _) if !(parent isRef defn.ArrayClass) => // @!!! eraseResult(parent) + case AppliedType(tycon, _) if !(tycon isRef defn.ArrayClass) => + eraseResult(tycon) case _ => this(tp) } @@ -530,10 +532,10 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else normalizeClass(sym.asClass).fullName.asTypeName case tp: AppliedType => - sigName(tp.superType) + sigName(if (tp.tycon.isRef(defn.ArrayClass)) this(tp) else tp.superType) case ErasedValueType(_, underlying) => sigName(underlying) - case defn.ArrayOf(elem) => + case defn.ArrayOf(elem) => // @!!! sigName(this(tp)) case tp: HKApply => sigName(tp.superType) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index b6fc6eee64a9..97211925314e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -45,21 +45,37 @@ 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) + } } - @tailrec - def argForParam(pre: Type, cls: Symbol, pref: TypeParamRef, prefCls: ClassSymbol): Type = - if (cls.is(PackageClass)) pref - else { - val base = pre.baseType(cls) - if (cls eq prefCls) { - val AppliedType(_, args) = base - args(pref.paramNum) - } - else argForParam(base.normalizedPrefix, cls.owner.enclosingClass, pref, prefCls) + @tailrec + def argForParam(pre: Type, cls: Symbol, tparam: Symbol): Type = { + def fail() = throw new TypeError(ex"$pre contains no matching argument for ${tparam.showLocated} ") + if ((pre eq NoType) || (pre eq NoPrefix) || (cls is PackageClass)) fail() + val base = pre.baseType(cls) + if (cls `eq` tparam.owner) { + var tparams = cls.typeParams + var args = base.argInfos + var idx = 0 + while (tparams.nonEmpty && args.nonEmpty) { + if (tparams.head.eq(tparam)) + return args.head match { + case bounds: TypeBounds => + val v = currentVariance + if (v > 0) bounds.hi + else if (v < 0) bounds.lo + else TypeArgRef(pre, cls.typeRef, idx) + case arg => arg + } + tparams = tparams.tail + args = args.tail + idx += 1 } + fail() + } + else argForParam(base.normalizedPrefix, cls.owner.enclosingClass, tparam) + } /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG // One `case ThisType` is specific to asSeenFrom, all other cases are inlined for performance @@ -116,7 +132,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } case _: ThisType | _: BoundType | NoPrefix => tp - case tp: RefinedType => + case tp: RefinedType => // @!!! tp.derivedRefinedType(simplify(tp.parent, theMap), tp.refinedName, simplify(tp.refinedInfo, theMap)) case tp: TypeAlias => tp.derivedTypeAlias(simplify(tp.alias, theMap)) @@ -194,6 +210,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def approximateOr(tp1: Type, tp2: Type): Type = { def isClassRef(tp: Type): Boolean = tp match { case tp: TypeRef => tp.symbol.isClass + case tp: AppliedType => isClassRef(tp.tycon) case tp: RefinedType => isClassRef(tp.parent) case _ => false } @@ -268,11 +285,11 @@ trait TypeOps { this: Context => // TODO: Make standalone object. cls.enter(sym, decls) } - /** Normalize a list of parent types of class `cls` that may contain refinements - * to a list of typerefs referring to classes, by converting all refinements to member - * definitions in scope `decls`. Can add members to `decls` as a side-effect. + /** Normalize a list of parent types of class `cls` to make sure they are + * all (possibly applied) references to classes. */ - def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[TypeRef] = { + def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[Type] = { + if (Config.newScheme) return parents.mapConserve(_.dealias) // println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG // A map consolidating all refinements arising from parent type parameters @@ -372,15 +389,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. paramBindings.foreachBinding(forwardRefs) } - /** Used only for debugging: All BaseTypeArg definitions in - * `cls` and all its base classes. - */ - def allBaseTypeArgs(cls: ClassSymbol)(implicit ctx: Context) = - for { bc <- cls.baseClasses - sym <- bc.info.decls.toList - if sym.is(BaseTypeArg) - } yield sym - /** An argument bounds violation is a triple consisting of * - the argument tree * - a string "upper" or "lower" indicating which bound is violated diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ca8ef59b92f0..45103161f73d 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1198,8 +1198,6 @@ object Types { /** 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 } @@ -2242,7 +2240,8 @@ object Types { abstract case class RefinedType(parent: Type, refinedName: Name, refinedInfo: Type) extends RefinedOrRecType { if (refinedName.isTermName) assert(refinedInfo.isInstanceOf[TermType]) - else assert(refinedInfo.isInstanceOf[TypeType]) + else assert(refinedInfo.isInstanceOf[TypeType], this) + if (Config.newScheme) assert(!refinedName.is(NameKinds.ExpandedName), this) override def underlying(implicit ctx: Context) = parent @@ -2558,11 +2557,12 @@ object Types { type ThisName <: Name type PInfo <: Type type This <: LambdaType{type PInfo = self.PInfo} + type ParamRefType <: ParamRef def paramNames: List[ThisName] def paramInfos: List[PInfo] def resType: Type - def newParamRef(n: Int): ParamRef + def newParamRef(n: Int): ParamRefType override def resultType(implicit ctx: Context) = resType @@ -2576,7 +2576,7 @@ object Types { final def isTypeLambda = isInstanceOf[TypeLambda] final def isHigherKinded = isInstanceOf[TypeProxy] - lazy val paramRefs: List[ParamRef] = paramNames.indices.toList.map(newParamRef) + lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef) protected def computeSignature(implicit ctx: Context) = resultSignature @@ -2647,6 +2647,7 @@ object Types { type ThisName = TermName type PInfo = Type type This <: TermLambda + type ParamRefType = TermParamRef override def resultType(implicit ctx: Context): Type = if (dependencyStatus == FalseDeps) { // dealias all false dependencies @@ -2886,6 +2887,7 @@ object Types { type ThisName = TypeName type PInfo = TypeBounds type This <: TypeLambda + type ParamRefType = TypeParamRef def isDependent(implicit ctx: Context): Boolean = true def isParamDependent(implicit ctx: Context): Boolean = true @@ -3037,7 +3039,7 @@ object Types { final val Provisional: DependencyStatus = 4 // set if dependency status can still change due to type variable instantiations } - // ----- HK types: LambdaParam, HKApply --------------------- + // ----- HK types: LambdaParam, HKApply, TypeArgRef --------------------- /** The parameter of a type lambda */ case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo { @@ -3206,6 +3208,24 @@ object Types { unique(new CachedHKApply(tycon, args)).checkInst } + /** A reference to wildcard argument `p.` + * where `p: C[... _ ...]` + */ + abstract case class TypeArgRef(prefix: Type, clsRef: TypeRef, idx: Int) extends CachedProxyType { + override def underlying(implicit ctx: Context): Type = + prefix.baseType(clsRef.symbol).argInfos.apply(idx) + def derivedTypeArgRef(prefix: Type)(implicit ctx: Context): Type = + if (prefix eq this.prefix) this else TypeArgRef(prefix, clsRef, idx) + override def computeHash = doHash(idx, prefix, clsRef) + } + + final class CachedTypeArgRef(prefix: Type, clsRef: TypeRef, idx: Int) extends TypeArgRef(prefix, clsRef, idx) + + object TypeArgRef { + def apply(prefix: Type, clsRef: TypeRef, idx: Int)(implicit ctx: Context) = + unique(new CachedTypeArgRef(prefix, clsRef, idx)) + } + // ----- BoundTypes: ParamRef, RecThis ---------------------------------------- abstract class BoundType extends CachedProxyType with ValueType { @@ -3417,7 +3437,7 @@ object Types { abstract case class ClassInfo( prefix: Type, cls: ClassSymbol, - classParents: List[TypeRef], + classParentsNEW: List[Type], decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { @@ -3442,14 +3462,16 @@ object Types { private var selfTypeCache: Type = null - private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match { - case tparam :: tparams1 => - fullyAppliedRef( - RefinedType(base, tparam.name, TypeRef(cls.thisType, tparam).toBounds(tparam)), - tparams1) - case nil => - base - } + private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = + if (Config.newScheme) base.appliedTo(tparams.map(_.typeRef)) + else tparams match { + case tparam :: tparams1 => + fullyAppliedRef( + RefinedType(base, tparam.name, TypeRef(cls.thisType, tparam).toBounds(tparam)), + tparams1) + case nil => + base + } /** The class type with all type parameters */ def fullyAppliedRef(implicit ctx: Context): Type = fullyAppliedRef(cls.typeRef, cls.typeParams) @@ -3468,18 +3490,17 @@ object Types { def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef(prefix, cls) // cached because baseType needs parents - private var parentsCache: List[TypeRef] = null + private var parentsCache: List[Type] = null /** The parent type refs as seen from the given prefix */ - override def parentRefs(implicit ctx: Context): List[TypeRef] = { - if (parentsCache == null) - parentsCache = cls.classParents.mapConserve(_.asSeenFrom(prefix, cls.owner).asInstanceOf[TypeRef]) - parentsCache - } + override def parentRefs(implicit ctx: Context): List[TypeRef] = + if (Config.newScheme) parentsNEW.map(_.typeConstructor.asInstanceOf[TypeRef]) + else parentsNEW.mapconserve(_.asInstanceOf[TypeRef]) /** The parent types with all type arguments */ override def parentsWithArgs(implicit ctx: Context): List[Type] = - parentRefs mapConserve { pref => + if (Config.newScheme) parentsNEW + else 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) @@ -3487,23 +3508,26 @@ object Types { } } - override def parentsNEW(implicit ctx: Context): List[Type] = - parentRefs // !!! TODO: change + override def parentsNEW(implicit ctx: Context): List[Type] = { + if (parentsCache == null) + parentsCache = classParentsNEW.mapConserve(_.asSeenFrom(prefix, cls.owner)) + parentsCache + } def derivedClassInfo(prefix: Type)(implicit ctx: Context) = if (prefix eq this.prefix) this - else ClassInfo(prefix, cls, classParents, decls, selfInfo) + else ClassInfo(prefix, cls, classParentsNEW, decls, selfInfo) - def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = - if ((prefix eq this.prefix) && (classParents eq this.classParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this - else ClassInfo(prefix, cls, classParents, decls, selfInfo) + def derivedClassInfo(prefix: Type = this.prefix, classParentsNEW: List[Type] = this.classParentsNEW, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = + if ((prefix eq this.prefix) && (classParentsNEW eq this.classParentsNEW) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this + else ClassInfo(prefix, cls, classParentsNEW, decls, selfInfo) override def computeHash = doHash(cls, prefix) override def toString = s"ClassInfo($prefix, $cls)" } - class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass) + class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: DotClass) extends ClassInfo(prefix, cls, classParents, decls, selfInfo) /** A class for temporary class infos where `parents` are not yet known. */ @@ -3519,14 +3543,14 @@ object Types { def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension /** Install classinfo with known parents in `denot` and resume all suspensions */ - def finalize(denot: SymDenotation, parents: List[TypeRef])(implicit ctx: Context) = { - denot.info = derivedClassInfo(classParents = parents) + def finalize(denot: SymDenotation, parents: List[Type])(implicit ctx: Context) = { + denot.info = derivedClassInfo(classParentsNEW = parents) suspensions.foreach(_(ctx)) } } object ClassInfo { - def apply(prefix: Type, cls: ClassSymbol, classParents: List[TypeRef], decls: Scope, selfInfo: DotClass = NoType)(implicit ctx: Context) = + def apply(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: DotClass = NoType)(implicit ctx: Context) = unique(new CachedClassInfo(prefix, cls, classParents, decls, selfInfo)) } @@ -3841,6 +3865,8 @@ object Types { tp.derivedAppliedType(tycon, args) protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = tp.derivedAppliedType(tycon, args) + protected def derivedTypeArgRef(tp: TypeArgRef, prefix: Type): Type = + tp.derivedTypeArgRef(prefix) protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type): Type = tp.derivedAndOrType(tp1, tp2) protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation): Type = @@ -3924,6 +3950,13 @@ object Types { } mapOverLambda + case tp @ TypeArgRef(prefix, _, _) => + val saved = variance + variance = 0 + val prefix1 = this(prefix) + variance = saved + derivedTypeArgRef(tp, prefix1) + case tp @ SuperType(thistp, supertp) => derivedSuperType(tp, this(thistp), this(supertp)) @@ -4220,6 +4253,13 @@ object Types { else range(lower(tp1) | lower(tp2), upper(tp1) | upper(tp2)) else tp.derivedAndOrType(tp1, tp2) + override protected def derivedTypeArgRef(tp: TypeArgRef, prefix: Type): Type = + if (prefix.exists) tp.derivedTypeArgRef(prefix) + else { + val paramBounds = tp.underlying + approx(paramBounds.loBound, paramBounds.hiBound) + } + override protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation) = underlying match { case Range(lo, hi) => @@ -4363,6 +4403,12 @@ object Types { case tp: SkolemType => this(x, tp.info) + case tp @ TypeArgRef(prefix, _, _) => + val saved = variance + variance = 0 + try this(x, prefix) + finally variance = saved + case AnnotatedType(underlying, annot) => this(applyToAnnot(x, annot), underlying) diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 585085f1d9e5..31519af93825 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -308,17 +308,12 @@ class ClassfileParser( case tp: TypeRef => if (sig(index) == '<') { accept('<') - var tp1: Type = tp - var formals: List[Symbol] = - if (skiptvs) - null - else - tp.typeParamSymbols + val argsBuf = if (skiptvs) null else new ListBuffer[Type] while (sig(index) != '>') { - sig(index) match { + val arg = sig(index) match { case variance @ ('+' | '-' | '*') => index += 1 - val bounds = variance match { + variance match { case '+' => objToAny(TypeBounds.upper(sig2type(tparams, skiptvs))) case '-' => val tp = sig2type(tparams, skiptvs) @@ -328,18 +323,24 @@ class ClassfileParser( else TypeBounds.lower(tp) case '*' => TypeBounds.empty } - if (formals != null) - tp1 = RefinedType(tp1, formals.head.name, bounds) // @!!! - case _ => - val info = sig2type(tparams, skiptvs) - if (formals != null) - tp1 = RefinedType(tp1, formals.head.name, TypeAlias(info)) // @!!! + case _ => sig2type(tparams, skiptvs) } - if (formals != null) - formals = formals.tail + if (argsBuf != null) argsBuf += arg } accept('>') - tp1 + if (skiptvs) tp + else if (config.Config.newScheme) tp.appliedTo(argsBuf.toList) + else { + var tp1: Type = tp + (argsBuf.toList, tp.typeParamSymbols).zipped.foreach { (arg, formal) => + val info = arg match { + case arg: TypeBounds => arg + case _ => TypeAlias(arg) + } + tp1 = RefinedType(tp1, formal.name, info) + } + tp1 + } } else tp case tp => assert(sig(index) != '<', tp) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index df8caa1b8653..6b57caaab057 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -164,10 +164,11 @@ Standard-Section: "ASTs" TopLevelStat* BIND Length boundName_NameRef bounds_Type // for type-variables defined in a type pattern BYNAMEtype underlying_Type + PARAMtype Length binder_ASTref paramNum_Nat + TYPEARGtype Length prefix_Type clsRef_Type idx_Nat POLYtype Length result_Type NamesTypes METHODtype Length result_Type NamesTypes // needed for refinements TYPELAMBDAtype Length result_Type NamesTypes // variance encoded in front of name: +/-/(nothing) - PARAMtype Length binder_ASTref paramNum_Nat // needed for refinements SHARED type_ASTRef NamesTypes = NameType* NameType = paramName_NameRef typeOrBounds_ASTRef @@ -380,6 +381,7 @@ object TastyFormat { final val LAMBDAtpt = 173 final val PARAMtype = 174 final val ANNOTATION = 175 + final val TYPEARGtype = 176 final val firstSimpleTreeTag = UNITconst final val firstNatTreeTag = SHARED @@ -562,6 +564,7 @@ object TastyFormat { case ENUMconst => "ENUMconst" case SINGLETONtpt => "SINGLETONtpt" case SUPERtype => "SUPERtype" + case TYPEARGtype => "TYPEARGtype" case REFINEDtype => "REFINEDtype" case REFINEDtpt => "REFINEDtpt" case APPLIEDtype => "APPLIEDtype" diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 3b8789ada24a..43756ddfa3fa 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -197,7 +197,10 @@ class TreePickler(pickler: TastyPickler) { } case tpe: SuperType => writeByte(SUPERtype) - withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe)} + withLength { pickleType(tpe.thistpe); pickleType(tpe.supertpe) } + case tpe: TypeArgRef => + writeByte(TYPEARGtype) + withLength { pickleType(tpe.prefix); pickleType(tpe.clsRef); writeNat(tpe.idx) } case tpe: RecThis => writeByte(RECthis) val binderAddr = pickledTypes.get(tpe.binder) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index bf3b593b9a94..12657342321c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -220,8 +220,6 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val result = (tag: @switch) match { - case SUPERtype => - SuperType(readType(), readType()) case REFINEDtype => var name: Name = readName() val parent = readType() @@ -247,6 +245,10 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi AndType(readType(), readType()) case ORtype => OrType(readType(), readType()) + case SUPERtype => + SuperType(readType(), readType()) + case TYPEARGtype => + TypeArgRef(readType(), readType().asInstanceOf[TypeRef], readNat()) case BIND => val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType()) registerSym(start, sym) @@ -713,7 +715,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi private def readTemplate(implicit ctx: Context): Template = { val start = currentAddr val cls = ctx.owner.asClass - def setClsInfo(parents: List[TypeRef], selfType: Type) = + def setClsInfo(parents: List[Type], selfType: Type) = cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType) val assumedSelfType = if (cls.is(Module) && cls.owner.isClass) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 8b716c5ff53d..f4589bcc6d2a 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -135,7 +135,7 @@ class PlainPrinter(_ctx: Context) extends Printer { */ private def refinementChain(tp: Type): List[Type] = tp :: (tp match { - case AnyAppliedType(_, _) => Nil + case AnyAppliedType(_, _) => Nil // @!!! case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) case _ => Nil }) @@ -166,6 +166,11 @@ class PlainPrinter(_ctx: Context) extends Printer { "{" ~ selfRecName(openRecs.length) ~ " => " ~ toTextGlobal(tp.parent) ~ "}" } finally openRecs = openRecs.tail + case TypeArgRef(prefix, clsRef, idx) => + val cls = clsRef.symbol + val tparams = cls.typeParams + val paramName = if (tparams.length > idx) nameString(tparams(idx)) else "" + toTextPrefix(prefix) ~ "" case AndType(tp1, tp2) => changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) } case OrType(tp1, tp2) => diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index e4db012bc0dd..a8b9ca2979f1 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -64,7 +64,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override protected def simpleNameString(sym: Symbol): String = { val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name - nameString(if (sym.is(TypeParam)) name.asTypeName.unexpandedName else name) + nameString(if (sym.is(TypeParam)) name.asTypeName.unexpandedName else name) // @!!! } override def fullNameString(sym: Symbol): String = diff --git a/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala index c9eefb22f75e..94c186a2ac19 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala @@ -81,8 +81,8 @@ class CheckReentrant extends MiniPhaseTransform { thisTransformer => sym.info.widenExpr.classSymbols.foreach(addVars) } } - for (parent <- cls.classInfo.classParents) - addVars(parent.symbol.asClass) + for (parent <- cls.classInfo.classParentsNEW) + addVars(parent.typeSymbol.asClass) } } } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 9db297324014..c3a864bdfafa 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -236,7 +236,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran // Add Child annotation to sealed parents unless current class is anonymous if (!sym.isAnonymousClass) // ignore anonymous class - sym.asClass.classInfo.classParents.foreach { parent => + sym.asClass.classParentsNEW.foreach { parent => val sym2 = if (sym.is(Module)) sym.sourceModule else sym registerChild(sym2, parent) } diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala b/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala index 8e47f84c17dc..e4f291679afa 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/InlineCaseIntrinsics.scala @@ -7,6 +7,7 @@ import core.StdNames._ import core.Symbols._ import core.Types._ import core.Flags._ +import core.TypeApplications.noBounds import ast.Trees._ import transform.SymUtils._ import Simplify.desugarIdent @@ -82,7 +83,7 @@ class InlineCaseIntrinsics(val simplifyPhase: Simplify) extends Optimisation { def some(e: Tree) = { val accessors = e.tpe.widenDealias.classSymbol.caseAccessors.filter(_.is(Method)) val fields = accessors.map(x => e.select(x).ensureApplied) - val tplType = a.tpe.baseArgTypes(defn.OptionClass).head + val tplType = noBounds(a.tpe.baseType(defn.OptionClass).argInfos.head) val someTpe = a.tpe.translateParameterized(defn.OptionClass, defn.SomeClass) if (fields.tail.nonEmpty) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index d79501c1cae0..54d3cdc2c5a4 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -98,7 +98,7 @@ object Applications { if (unapplyName == nme.unapplySeq) { if (unapplyResult derivesFrom defn.SeqClass) seqSelector :: Nil else if (isGetMatch(unapplyResult, pos)) { - val seqArg = boundsToHi(getTp.elemType) + val seqArg = getTp.elemType.hiBound if (seqArg.exists) args.map(Function.const(seqArg)) else fail } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 31585337b073..11452b7c8bab 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -455,7 +455,7 @@ object Checking { case tp: ClassInfo => tp.derivedClassInfo( prefix = apply(tp.prefix), - classParents = + classParentsNEW = tp.parentsWithArgs.map { p => apply(p).underlyingClassRef(refinementOK = false) match { case ref: TypeRef => ref @@ -580,17 +580,26 @@ trait Checking { * their lower bound conforms to their upper bound. If a type argument is * infeasible, issue and error and continue with upper bound. */ - def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match { - case tp: RefinedType => - tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where)) - case tp: RecType => - tp.rebind(tp.parent) - case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => - ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) - TypeAlias(hi) - case _ => - tp - } + def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = + tp match { + case tp @ AppliedType(tycon, args) => + def checkArg(arg: Type) = arg match { + case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => + ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) + hi + case _ => arg + } + tp.derivedAppliedType(tycon, args.mapConserve(checkArg)) + case tp: RefinedType => // @!!! + tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where)) + case tp: RecType => // @!!! + tp.rebind(tp.parent) + case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => // @!!! + ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) + TypeAlias(hi) + case _ => + tp + } /** Check that `tree` is a pure expression of constant type */ def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit = diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 46452a065a19..575bbc8d970e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -438,14 +438,14 @@ trait ImplicitRunInfo { self: RunInfo => else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } - def addParentScope(parent: TypeRef): Unit = { - iscopeRefs(parent) foreach addRef + def addParentScope(parent: Type): Unit = { + iscopeRefs(parent.typeConstructor) foreach addRef for (param <- parent.typeParamSymbols) comps ++= iscopeRefs(tp.member(param.name).info) } val companion = cls.companionModule if (companion.exists) addRef(companion.valRef) - cls.classParents foreach addParentScope + cls.classParentsNEW foreach addParentScope } tp.classSymbols(liftingCtx) foreach addClassScope case _ => @@ -942,10 +942,12 @@ trait Implicits { self: Typer => */ class SearchHistory(val searchDepth: Int, val seen: Map[ClassSymbol, Int]) { - /** The number of RefinementTypes in this type, after all aliases are expanded */ + /** The number of applications and refinements in this type, after all aliases are expanded */ private def typeSize(tp: Type)(implicit ctx: Context): Int = { val accu = new TypeAccumulator[Int] { def apply(n: Int, tp: Type): Int = tp match { + case tp: AppliedType => + foldOver(n + 1, tp) case tp: RefinedType => foldOver(n + 1, tp) case tp: TypeRef if tp.info.isAlias => diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 741e174d3ec2..8c0aab5a51ad 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -100,7 +100,7 @@ object RefChecks { ctx.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), cls.pos) } - for (parent <- cinfo.classParents) + for (parent <- cinfo.classParentsNEW) checkSelfConforms(parent.typeSymbol.asClass, "illegal inheritance", "parent") for (reqd <- cinfo.cls.givenSelfType.classSymbols) checkSelfConforms(reqd, "missing requirement", "required") @@ -251,7 +251,7 @@ object RefChecks { def compatibleTypes(memberTp: Type, otherTp: Type): Boolean = try if (member.isType) // intersection of bounds to refined types must be nonempty - member.is(BaseTypeArg) || + member.is(BaseTypeArg) || // @!!! memberTp.bounds.hi.hasSameKindAs(otherTp.bounds.hi) && ((memberTp frozen_<:< otherTp) || !member.owner.derivesFrom(other.owner) && { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c7b34f618e74..6a000e6ea776 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1421,7 +1421,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } // Check that phantom lattices are defined in a static object - if (cls.classParents.exists(_.classSymbol eq defn.PhantomClass) && !cls.isStaticOwner) + if (cls.classParentsNEW.exists(_.typeSymbol eq defn.PhantomClass) && !cls.isStaticOwner) ctx.error("only static objects can extend scala.Phantom", cdef.pos) // check value class constraints @@ -1454,8 +1454,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def realClassParent(cls: Symbol): ClassSymbol = if (!cls.isClass) defn.ObjectClass else if (!(cls is Trait)) cls.asClass - else cls.asClass.classParents match { - case parentRef :: _ => realClassParent(parentRef.symbol) + else cls.asClass.classParentsNEW match { + case parentRef :: _ => realClassParent(parentRef.typeSymbol) case nil => defn.ObjectClass } def improve(candidate: ClassSymbol, parent: Type): ClassSymbol = { @@ -2040,13 +2040,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit // Follow proxies and approximate type paramrefs by their upper bound // in the current constraint in order to figure out robustly // whether an expected type is some sort of function type. - def underlyingRefined(tp: Type): Type = tp.stripTypeVar match { + def underlyingApplied(tp: Type): Type = tp.stripTypeVar match { case tp: RefinedType => tp - case tp: TypeParamRef => underlyingRefined(ctx.typeComparer.bounds(tp).hi) - case tp: TypeProxy => underlyingRefined(tp.superType) + case tp: AppliedType => tp + case tp: TypeParamRef => underlyingApplied(ctx.typeComparer.bounds(tp).hi) + case tp: TypeProxy => underlyingApplied(tp.superType) case _ => tp } - val ptNorm = underlyingRefined(pt) + val ptNorm = underlyingApplied(pt) val arity = if (defn.isFunctionType(ptNorm)) if (!isFullyDefined(pt, ForceDegree.none) && isFullyDefined(wtp, ForceDegree.none)) diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 705a06580a89..2e14b83bceb1 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -198,7 +198,7 @@ object factories { case _ => false } - cd.classParents.collect { + cd.classParentRefs.collect { case t: TypeRef if !isJavaLangObject(t) && !isProductWithArity(t) => UnsetLink(t.name.toString, path(t.symbol).mkString(".")) } From 4b64c00ddc1f9bd1a97db4a707c23bddda3db0ee Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Jul 2017 14:11:40 +0200 Subject: [PATCH 006/146] Various fixes --- .../src/dotty/tools/dotc/core/Contexts.scala | 5 +++-- .../dotty/tools/dotc/core/SymDenotations.scala | 6 +++--- .../tools/dotc/core/TypeApplications.scala | 2 +- .../src/dotty/tools/dotc/core/TypeOps.scala | 18 +++++++++--------- compiler/src/dotty/tools/dotc/core/Types.scala | 7 ++++++- .../dotc/core/classfile/ClassfileParser.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 12 ++++++++++-- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- 9 files changed, 35 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index fb60245efa37..d5fccd928643 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -14,7 +14,6 @@ import NameOps._ import Uniques._ import SymDenotations._ import Comments._ -import Flags.ParamAccessor import util.Positions._ import ast.Trees._ import ast.untpd @@ -339,7 +338,9 @@ object Contexts { * from constructor parameters to class parameter accessors. */ def superCallContext: Context = { - val locals = newScopeWith(owner.asClass.paramAccessors: _*) + val locals = newScopeWith( + (if (Config.newScheme) owner.typeParams ++ owner.asClass.paramAccessors + else owner.asClass.paramAccessors): _*) superOrThisCallContext(owner.primaryConstructor, locals) } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index d95f44e6156d..0ea3e4bfa163 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1731,11 +1731,11 @@ object SymDenotations { else constrNamed(nme.CONSTRUCTOR).orElse(constrNamed(nme.TRAIT_CONSTRUCTOR)) } - /** The parameter accessors of this class. Term and type accessors, - * getters and setters are all returned int his list + /** The term parameter accessors of this class. + * Both getters and setters are returned in this list. */ def paramAccessors(implicit ctx: Context): List[Symbol] = - unforcedDecls.filter(_ is ParamAccessor).toList + unforcedDecls.filter(_.is(ParamAccessor)).toList /** If this class has the same `decls` scope reference in `phase` and * `phase.next`, install a new denotation with a cloned scope in `phase.next`. diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index b1807f9e2a4c..79da18fe2326 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -515,7 +515,7 @@ class TypeApplications(val self: Type) extends AnyVal { case TypeBounds(_, hi) => hi.baseTypeWithArgs(base) case _ => default } - case tp @ RefinedType(parent, name, _) if !isExpandedTypeParam(tp.member(name).symbol) => + case tp @ RefinedType(parent, name, _) if !Config.newScheme && !isExpandedTypeParam(tp.member(name).symbol) => tp.wrapIfMember(parent.baseTypeWithArgs(base)) case tp: TermRef => tp.underlying.baseTypeWithArgs(base) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 97211925314e..7bd716ed8aba 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -81,18 +81,18 @@ trait TypeOps { this: Context => // TODO: Make standalone object. // One `case ThisType` is specific to asSeenFrom, all other cases are inlined for performance tp match { case tp: NamedType => - if (tp.symbol.isStatic) tp - else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix))) + val sym = tp.symbol + if (sym.isStatic) tp + else { + val pre1 = atVariance(variance max 0)(this(tp.prefix)) + if (Config.newScheme && sym.is(TypeParam)) argForParam(pre1, cls, sym) + else derivedSelect(tp, pre1) + } case tp: ThisType => toPrefix(pre, cls, tp.cls) - case tp: TypeParamRef => - tp.binder.resultType match { - case cinfo: ClassInfo => argForParam(pre, cls, tp, cinfo.cls) - case _ => tp - } case _: BoundType | NoPrefix => tp - case tp: RefinedType => + case tp: RefinedType => //@!!! derivedRefinedType(tp, apply(tp.parent), apply(tp.refinedInfo)) case tp: TypeAlias if tp.variance == 1 => // if variance != 1, need to do the variance calculation derivedTypeAlias(tp, apply(tp.alias)) @@ -103,7 +103,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } override def reapply(tp: Type) = - // derives infos have already been subjected to asSeenFrom, hence to need to apply the map again. + // derived infos have already been subjected to asSeenFrom, hence to need to apply the map again. tp } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 45103161f73d..b5adf3f53c55 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -601,6 +601,8 @@ object Types { case tl: HKTypeLambda => go(tl.resType).mapInfo(info => tl.derivedLambdaAbstraction(tl.paramNames, tl.paramInfos, info).appliedTo(tp.args)) + case tc: TypeRef if tc.symbol.isClass => + go(tc) case _ => go(tp.superType) } @@ -1198,7 +1200,10 @@ object Types { /** The full parent types, including (in new scheme) all type arguments */ def parentsNEW(implicit ctx: Context): List[Type] = this match { - case tp: TypeProxy => tp.superType.parentsNEW + case tp @ AppliedType(tycon, args) if tycon.typeSymbol.isClass => + tycon.parentsNEW.map(_.subst(tycon.typeSymbol.typeParams, args)) + case tp: TypeProxy => + tp.superType.parentsNEW case _ => Nil } diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 31519af93825..91e6b2776c95 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -424,7 +424,7 @@ class ClassfileParser( val start = index while (sig(index) != '>') { val tpname = subName(':'.==).toTypeName - val expname = if (owner.isClass) tpname.expandedName(owner) else tpname + val expname = if (owner.isClass && !config.Config.newScheme) tpname.expandedName(owner) else tpname val s = ctx.newSymbol( owner, expname, owner.typeParamCreationFlags, typeParamCompleter(index), coord = indexCoord(index)) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index f9ce4f07b9ab..70a6a56ce5ec 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -486,7 +486,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas var name1 = name.asTypeName var flags1 = flags if (flags is TypeParam) { - name1 = name1.expandedName(owner) + if (!dotty.tools.dotc.config.Config.newScheme) name1 = name1.expandedName(owner) flags1 |= owner.typeParamCreationFlags } ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 11452b7c8bab..e98bb525b63c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -426,7 +426,7 @@ object Checking { * @pre The signature of `sym` refers to `other` */ def isLeaked(other: Symbol) = - other.is(Private) && { + other.is(Private, butNot = TypeParam) && { val otherBoundary = other.owner val otherLinkedBoundary = otherBoundary.linkedClass !(symBoundary.isContainedIn(otherBoundary) || @@ -456,6 +456,14 @@ object Checking { tp.derivedClassInfo( prefix = apply(tp.prefix), classParentsNEW = + if (config.Config.newScheme) + tp.parentsWithArgs.map { p => + apply(p).stripAnnots match { + case ref: RefType => ref + case _ => defn.ObjectType // can happen if class files are missing + } + } + else tp.parentsWithArgs.map { p => apply(p).underlyingClassRef(refinementOK = false) match { case ref: TypeRef => ref @@ -498,7 +506,7 @@ object Checking { ctx.error(ValueClassesMayNotWrapItself(clazz), clazz.pos) else { val clParamAccessors = clazz.asClass.paramAccessors.filter { param => - param.isTerm && !param.is(Flags.Accessor) + param.isTerm && !param.is(Flags.Accessor) // @!!! } clParamAccessors match { case param :: params => diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 0993e30cd4d9..976882a717cd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -915,7 +915,7 @@ class Namer { typer: Typer => val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_))) val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls) - typr.println(s"completing $denot, parents = $parents, parentTypes = $parentTypes, parentRefs = $parentRefs") + typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %, parentRefs = $parentRefs%, %") tempInfo.finalize(denot, parentRefs) From 76d11948a3ba684b4f02829bdd21d74b90a36ced Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Jul 2017 16:34:38 +0200 Subject: [PATCH 007/146] More fixes --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- .../src/dotty/tools/dotc/config/Config.scala | 4 +- .../tools/dotc/core/ConstraintHandling.scala | 2 - .../dotty/tools/dotc/core/Denotations.scala | 4 ++ .../tools/dotc/core/SymDenotations.scala | 11 +++- .../tools/dotc/core/TypeApplications.scala | 6 ++- .../dotty/tools/dotc/core/TypeComparer.scala | 1 + .../src/dotty/tools/dotc/core/TypeOps.scala | 53 +++++++++---------- .../src/dotty/tools/dotc/core/Types.scala | 38 +++++++++---- .../tools/dotc/interactive/Interactive.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotc/transform/FunctionalInterfaces.scala | 2 +- .../dotty/tools/dotc/transform/Splitter.scala | 2 +- .../tools/dotc/transform/SuperAccessors.scala | 6 +-- .../dotc/transform/SyntheticMethods.scala | 2 +- .../dotty/tools/dotc/transform/TailRec.scala | 4 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../dotty/tools/dotc/typer/RefChecks.scala | 1 + .../dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 21 files changed, 90 insertions(+), 60 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 4ee30af5ede1..8a179ada87cb 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -214,7 +214,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = { val firstParentRef :: otherParentRefs = cls.info.parentRefs - val firstParent = cls.typeRef.baseTypeWithArgs(firstParentRef.symbol) + val firstParent = cls.appliedRef.baseTypeWithArgs(firstParentRef.symbol) val superRef = if (cls is Trait) TypeTree(firstParent) else { diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 22f36dfea790..58d152de1f6d 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -79,7 +79,7 @@ object Config { final val traceDeepSubTypeRecursions = false /** When explaining subtypes and this flag is set, also show the classes of the compared types. */ - final val verboseExplainSubtype = false + final val verboseExplainSubtype = true /** If this flag is set, take the fast path when comparing same-named type-aliases and types */ final val fastPathForRefinedSubtype = true @@ -175,5 +175,5 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - final val newScheme = false + final val newScheme = true } diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index b11a2caaf0ff..06c56c9ef3a3 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -202,8 +202,6 @@ trait ConstraintHandling { tp.derivedAppliedType(tycon, args.zipWithConserve(tycon.typeParams)(avoidInArg)) case tp: RefinedType if param occursIn tp.refinedInfo => - assert(fromBelow || variance <= 0, - "unsound approximation of $param with bounds ${constraint.fullUpperBound(param)}") tp.parent case tp: WildcardType => val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 14a93191e4a6..7f89006721fd 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -644,6 +644,10 @@ object Denotations { // ------ Forming types ------------------------------------------- /** The TypeRef representing this type denotation at its original location. */ + def appliedRef(implicit ctx: Context): Type = + if (Config.newScheme) typeRef.appliedTo(symbol.typeParams.map(_.typeRef)) + else typeRef + def typeRef(implicit ctx: Context): TypeRef = TypeRef(symbol.owner.thisType, symbol.name.asTypeName, this) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0ea3e4bfa163..c3a0d7d56a7e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1427,7 +1427,14 @@ object SymDenotations { else ThisType.raw(TypeRef(pre, symbol.asType)) } */ - private[this] var myTypeRef: TypeRef = null + private[this] var myAppliedRef: Type = null // @!!!: Use classInfo.appliedRef instead? + private[this] var myTypeRef: TypeRef = null // @!!!: Use classInfo.appliedRef instead? + + override def appliedRef(implicit ctx: Context): Type = { + if (myAppliedRef == null) myAppliedRef = super.appliedRef + if (ctx.erasedTypes) myAppliedRef.typeConstructor + else myAppliedRef + } override def typeRef(implicit ctx: Context): TypeRef = { if (myTypeRef == null) myTypeRef = super.typeRef @@ -1635,7 +1642,7 @@ object SymDenotations { def computeBaseTypeOf(tp: Type): Type = { Stats.record("computeBaseTypeOf") if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty) - symbol.typeRef + symbol.appliedRef else tp match { case tp: RefType => val subcls = tp.symbol diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 79da18fe2326..622e163ea477 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -221,6 +221,8 @@ class TypeApplications(val self: Type) extends AnyVal { Nil case self: WildcardType => self.optBounds.typeParams + case self: AppliedType => + Nil case self: TypeProxy => self.superType.typeParams case _ => @@ -292,7 +294,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = { val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParamSymbols - HKTypeLambda.fromParams(tparamsToUse, self.appliedTo(tparams map (_.typeRef))) + HKTypeLambda.fromParams(tparamsToUse, self.appliedTo(tparams.map(_.typeRef))) //.ensuring(res => res.EtaReduce =:= self, s"res = $res, core = ${res.EtaReduce}, self = $self, hc = ${res.hashCode}") } @@ -539,7 +541,7 @@ class TypeApplications(val self: Type) extends AnyVal { self.derivedExprType(tp.translateParameterized(from, to)) case _ => if (self.derivesFrom(from)) - if (ctx.erasedTypes) to.typeRef + if (ctx.erasedTypes) to.typeRef // @!!! can be dropped; appliedTo does the right thing anyway else if (Config.newScheme) to.typeRef.appliedTo(self.baseType(from).argInfos) else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) else self diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index d29c4d01b027..7b6bb8e8c8ea 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -566,6 +566,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def isNullable(tp: Type): Boolean = tp.widenDealias match { case tp: TypeRef => tp.symbol.isNullableClass case tp: RefinedOrRecType => isNullable(tp.parent) + case tp: AppliedType => isNullable(tp.tycon) case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2) case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2) case _ => false diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 7bd716ed8aba..aea3d1ac9645 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -49,43 +49,42 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } - @tailrec - def argForParam(pre: Type, cls: Symbol, tparam: Symbol): Type = { - def fail() = throw new TypeError(ex"$pre contains no matching argument for ${tparam.showLocated} ") - if ((pre eq NoType) || (pre eq NoPrefix) || (cls is PackageClass)) fail() - val base = pre.baseType(cls) - if (cls `eq` tparam.owner) { - var tparams = cls.typeParams - var args = base.argInfos - var idx = 0 - while (tparams.nonEmpty && args.nonEmpty) { - if (tparams.head.eq(tparam)) - return args.head match { - case bounds: TypeBounds => - val v = currentVariance - if (v > 0) bounds.hi - else if (v < 0) bounds.lo - else TypeArgRef(pre, cls.typeRef, idx) - case arg => arg - } - tparams = tparams.tail - args = args.tail - idx += 1 - } - fail() + def argForParam(pre: Type, tparam: Symbol): Type = { + val tparamCls = tparam.owner + pre.baseType(tparamCls) match { + case AppliedType(_, allArgs) => + var tparams = tparamCls.typeParams + var args = allArgs + var idx = 0 + while (tparams.nonEmpty && args.nonEmpty) { + if (tparams.head.eq(tparam)) + return args.head match { + case bounds: TypeBounds => + val v = currentVariance + if (v > 0) bounds.hi + else if (v < 0) bounds.lo + else TypeArgRef(pre, cls.typeRef, idx) + case arg => arg + } + tparams = tparams.tail + args = args.tail + idx += 1 + } + throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") + case OrType(tp1, tp2) => argForParam(tp1, cls) | argForParam(tp2, cls) + case AndType(tp1, tp2) => argForParam(tp1, cls) & argForParam(tp2, cls) + case _ => tp } - else argForParam(base.normalizedPrefix, cls.owner.enclosingClass, tparam) } /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG - // One `case ThisType` is specific to asSeenFrom, all other cases are inlined for performance tp match { case tp: NamedType => val sym = tp.symbol if (sym.isStatic) tp else { val pre1 = atVariance(variance max 0)(this(tp.prefix)) - if (Config.newScheme && sym.is(TypeParam)) argForParam(pre1, cls, sym) + if (Config.newScheme && sym.is(TypeParam)) argForParam(pre1, sym) else derivedSelect(tp, pre1) } case tp: ThisType => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b5adf3f53c55..55b734a3bad3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -472,7 +472,7 @@ object Types { // We need a valid prefix for `asSeenFrom` val pre = this match { case tp: ClassInfo => - tp.typeRef + tp.typeRef // @!!! appliedRef case _ => widenIfUnstable } @@ -1258,7 +1258,7 @@ object Types { /** This type seen as a TypeBounds */ final def bounds(implicit ctx: Context): TypeBounds = this match { case tp: TypeBounds => tp - case ci: ClassInfo => TypeAlias(ci.typeRef) + case ci: ClassInfo => TypeAlias(ci.appliedRef) case wc: WildcardType => wc.optBounds match { case bounds: TypeBounds => bounds @@ -2024,7 +2024,7 @@ object Types { // Those classes are non final as Linker extends them. class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym - class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym + class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym { /** Assert current phase does not have erasure semantics */ private def assertUnerased()(implicit ctx: Context) = @@ -3072,14 +3072,16 @@ object Types { if (ctx.period != validSuper) { validSuper = ctx.period cachedSuper = tycon match { - case tp: HKTypeLambda => defn.AnyType - case tp: TypeVar if !tp.inst.exists => + case tycon: HKTypeLambda => defn.AnyType + case tycon: TypeVar if !tycon.inst.exists => // supertype not stable, since underlying might change validSuper = Nowhere - tp.underlying.applyIfParameterized(args) - case tp: TypeProxy => - if (tp.typeSymbol.is(Provisional)) validSuper = Nowhere - tp.superType.applyIfParameterized(args) + tycon.underlying.applyIfParameterized(args) + case tycon: TypeProxy => + val sym = tycon.typeSymbol + if (sym.is(Provisional)) validSuper = Nowhere + if (sym.isClass) tycon + else tycon.superType.applyIfParameterized(args) case _ => defn.AnyType } } @@ -3479,8 +3481,11 @@ object Types { } /** The class type with all type parameters */ - def fullyAppliedRef(implicit ctx: Context): Type = fullyAppliedRef(cls.typeRef, cls.typeParams) + def fullyAppliedRef(implicit ctx: Context): Type = + if (Config.newScheme && false) cls.appliedRef + else fullyAppliedRef(cls.typeRef, cls.typeParams) + private var appliedRefCache: Type = null private var typeRefCache: TypeRef = null def typeRef(implicit ctx: Context): TypeRef = { @@ -3492,6 +3497,19 @@ object Types { typeRefCache } + 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 + else TypeRef(prefix, cls.name, clsDenot) + appliedRefCache = + if (Config.newScheme) tref.appliedTo(cls.typeParams.map(_.typeRef)) + else tref + } + appliedRefCache + } + def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef(prefix, cls) // cached because baseType needs parents diff --git a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala index fc6def3190ee..e0eee6a721a9 100644 --- a/compiler/src/dotty/tools/dotc/interactive/Interactive.scala +++ b/compiler/src/dotty/tools/dotc/interactive/Interactive.scala @@ -78,7 +78,7 @@ object Interactive { def scopeCompletions: List[Symbol] = boundary.enclosingClass match { case csym: ClassSymbol => - val classRef = csym.classInfo.typeRef + val classRef = csym.classInfo.appliedRef completions(classRef, boundary) case _ => Nil diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 8573e1e930d9..cb10173dd554 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -157,7 +157,7 @@ object ExplicitOuter { /** A new outer accessor or param accessor */ private def newOuterSym(owner: ClassSymbol, cls: ClassSymbol, name: TermName, flags: FlagSet)(implicit ctx: Context) = { - val target = cls.owner.enclosingClass.typeRef + val target = cls.owner.enclosingClass.appliedRef val info = if (flags.is(Method)) ExprType(target) else target ctx.withPhaseNoEarlier(ctx.explicitOuterPhase.next) // outer accessors are entered at explicitOuter + 1, should not be defined before. .newSymbol(owner, name, Synthetic | flags, info, coord = cls.coord) diff --git a/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala b/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala index bde902152414..d8920fc6b043 100644 --- a/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala +++ b/compiler/src/dotty/tools/dotc/transform/FunctionalInterfaces.scala @@ -72,7 +72,7 @@ class FunctionalInterfaces extends MiniPhaseTransform { // symbols loaded from classpath aren't defined in periods earlier than when they where loaded val interface = ctx.withPhase(ctx.typerPhase).getClassIfDefined(functionPackage ++ interfaceName) if (interface.exists) { - val tpt = tpd.TypeTree(interface.asType.typeRef) + val tpt = tpd.TypeTree(interface.asType.appliedRef) tpd.Closure(tree.env, tree.meth, tpt) } else tree } else tree diff --git a/compiler/src/dotty/tools/dotc/transform/Splitter.scala b/compiler/src/dotty/tools/dotc/transform/Splitter.scala index d62be1a827e0..dbd9f15e8532 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splitter.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splitter.scala @@ -92,7 +92,7 @@ class Splitter extends MiniPhaseTransform { thisTransform => else { def choose(qual: Tree, syms: List[Symbol]): Tree = { def testOrCast(which: Symbol, mbr: Symbol) = - qual.select(which).appliedToType(mbr.owner.typeRef) + qual.select(which).appliedToType(mbr.owner.appliedRef) def select(sym: Symbol) = { val qual1 = if (qual.tpe derivesFrom sym.owner) qual diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 9a505ce8d49e..7e59b770e02c 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -297,7 +297,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val clazz = currentClass val host = hostForAccessorOf(sym, clazz) def accessibleThroughSubclassing = - validCurrentClass && (clazz.classInfo.selfType <:< sym.owner.typeRef) && !clazz.is(Trait) + validCurrentClass && (clazz.classInfo.selfType <:< sym.owner.appliedRef) && !clazz.is(Trait) val isCandidate = ( sym.is(Protected) @@ -308,7 +308,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { && (sym.enclosingPackageClass == sym.accessBoundary(sym.enclosingPackageClass)) ) val hostSelfType = host.classInfo.selfType - def isSelfType = !(host.typeRef <:< hostSelfType) && { + def isSelfType = !(host.appliedRef <:< hostSelfType) && { if (hostSelfType.typeSymbol.is(JavaDefined)) ctx.restrictionError( s"cannot accesses protected $sym from within $clazz with host self type $hostSelfType", pos) @@ -332,7 +332,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { */ private def hostForAccessorOf(sym: Symbol, referencingClass: ClassSymbol)(implicit ctx: Context): ClassSymbol = if (referencingClass.derivesFrom(sym.owner) - || referencingClass.classInfo.selfType <:< sym.owner.typeRef + || referencingClass.classInfo.selfType <:< sym.owner.appliedRef || referencingClass.enclosingPackageClass == sym.owner.enclosingPackageClass) { assert(referencingClass.isClass, referencingClass) referencingClass diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala index 20a8a08b40d3..3faaaa7f1b8e 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -54,7 +54,7 @@ class SyntheticMethods(thisTransformer: DenotTransformer) { /** The synthetic methods of the case or value class `clazz`. */ def syntheticMethods(clazz: ClassSymbol)(implicit ctx: Context): List[Tree] = { - val clazzType = clazz.typeRef + val clazzType = clazz.appliedRef lazy val accessors = if (isDerivedValueClass(clazz)) clazz.termParamAccessors diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 10c18e165dfb..906a9d5c3ad7 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -244,7 +244,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete if (isRecursiveCall) { if (ctx.tailPos) { - val receiverIsSame = enclosingClass.typeRef.widenDealias =:= recvWiden + val receiverIsSame = enclosingClass.appliedRef.widenDealias =:= recvWiden val receiverIsThis = prefix.tpe =:= thisType || prefix.tpe.widen =:= thisType def rewriteTailCall(recv: Tree): Tree = { @@ -282,7 +282,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete } else fail(defaultReason) } else { - val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recvWiden + val receiverIsSuper = (method.name eq sym) && enclosingClass.appliedRef.widen <:< recvWiden if (receiverIsSuper) fail("it contains a recursive call targeting a supertype") else continue diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 54d3cdc2c5a4..abad8e78a6df 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1096,7 +1096,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] case tp1: PolyType => // (2) val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, tp1.instantiateBounds) - isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2) + isAsSpecific(alt1, tp1.instantiate(tparams.map(_.typeRef)), alt2, tp2) case _ => // (3) tp2 match { case tp2: MethodType => true // (3a) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 976882a717cd..5846c40091b1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -92,7 +92,7 @@ trait NamerContextOps { this: Context => * type of the constructed instance is returned */ def effectiveResultType(sym: Symbol, typeParams: List[Symbol], given: Type) = - if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams map (_.typeRef)) + if (sym.name == nme.CONSTRUCTOR) sym.owner.typeRef.appliedTo(typeParams.map(_.typeRef)) else given /** if isConstructor, make sure it has one non-implicit parameter list */ diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 8c0aab5a51ad..b52891ccddef 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -84,6 +84,7 @@ object RefChecks { */ private def upwardsThisType(cls: Symbol)(implicit ctx: Context) = cls.info match { case ClassInfo(_, _, _, _, tp: Type) if (tp ne cls.typeRef) && !cls.is(ModuleOrFinal) => + // @!!! case ClassInfo(_, _, _, _, selfTp: Type) if selfTp.exists && !cls.is(ModuleOrFinal) => SkolemType(cls.typeRef).withName(nme.this_) case _ => cls.thisType diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index b8706b953aa1..4485e6ff6e52 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -306,7 +306,7 @@ trait TypeAssigner { errorType("ambiguous parent class qualifier", tree.pos) } val owntype = - if (mixinClass.exists) mixinClass.typeRef + if (mixinClass.exists) mixinClass.appliedRef else if (!mix.isEmpty) findMixinSuper(cls.info) else if (inConstrCall || ctx.erasedTypes) cls.info.firstParentRef else { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 6a000e6ea776..340c125b5512 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1412,7 +1412,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) .withType(dummy.nonMemberTermRef) checkVariance(impl1) - if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.thisType, cdef.namePos) + if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.appliedRef, cdef.namePos) val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls) if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) From cf491ff8e65ca1bf1172b83384fef911d02aff8d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Jul 2017 12:58:21 +0200 Subject: [PATCH 008/146] Fix stray brace --- compiler/src/dotty/tools/dotc/core/Types.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 55b734a3bad3..00e5da305110 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2024,7 +2024,7 @@ object Types { // Those classes are non final as Linker extends them. class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym - class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym { + class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym /** Assert current phase does not have erasure semantics */ private def assertUnerased()(implicit ctx: Context) = @@ -2708,7 +2708,7 @@ object Types { * def f(x: C)(y: x.S) // dependencyStatus = TrueDeps * def f(x: C)(y: x.T) // dependencyStatus = FalseDeps, i.e. * // dependency can be eliminated by dealiasing. - */ + */ private def dependencyStatus(implicit ctx: Context): DependencyStatus = { if (myDependencyStatus != Unknown) myDependencyStatus else { From 08ff2b2ec816d30d5411ca45813b7937b363df15 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Jul 2017 12:43:05 +0200 Subject: [PATCH 009/146] Fix typing of _* arguments --- .../tools/dotc/core/TypeApplications.scala | 19 +++++++++++++++++-- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 622e163ea477..7819e882e693 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -160,10 +160,25 @@ object TypeApplications { p.binder == tycon && args(p.paramNum).isInstanceOf[TypeBounds] def canReduceWildcard(p: TypeParamRef) = !ctx.mode.is(Mode.AllowLambdaWildcardApply) || available.contains(p.paramNum) - def apply(t: Type) = t match { - case t @ TypeAlias(p: TypeParamRef) if hasWildcardArg(p) && canReduceWildcard(p) => + + // If this is a reference to a reducable type parameter corresponding to a + // wildcard argument, return the wildcard argument, otherwise apply recursively. + def applyArg(arg: Type): Type = arg match { + case p: TypeParamRef if hasWildcardArg(p) && canReduceWildcard(p) => available -= p.paramNum args(p.paramNum) + case _ => + apply(arg) + } + + def apply(t: Type) = t match { + case t @ TypeAlias(alias) => + applyArg(alias) match { + case arg1: TypeBounds => arg1 + case arg1 => t.derivedTypeAlias(arg1) + } + case t @ AppliedType(tycon, args1) if tycon.typeSymbol.isClass => + t.derivedAppliedType(apply(tycon), args1.mapConserve(applyArg)) case p: TypeParamRef if p.binder == tycon => args(p.paramNum) match { case TypeBounds(lo, hi) => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 340c125b5512..2851ae43979f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -519,7 +519,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (untpd.isWildcardStarArg(tree)) cases( ifPat = ascription(TypeTree(defn.RepeatedParamType.appliedTo(pt)), isWildcard = true), - ifExpr = seqToRepeated(typedExpr(tree.expr, defn.SeqType)), + ifExpr = seqToRepeated(typedExpr(tree.expr, defn.SeqType.appliedTo(defn.AnyType))), wildName = nme.WILDCARD_STAR) else { def typedTpt = checkSimpleKinded(typedType(tree.tpt)) From b17f5de727ad5639a3b60fcfb2cd0447ffc7c809 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 16:51:40 +0200 Subject: [PATCH 010/146] Fix rebase breakage --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 6 +++--- compiler/src/dotty/tools/dotc/core/Types.scala | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 8a179ada87cb..488aff9f8f1c 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.parentRefs + val firstParentRef :: otherParentRefs = cls.info.parentRefs // @!!! adapt val firstParent = cls.appliedRef.baseTypeWithArgs(firstParentRef.symbol) val superRef = if (cls is Trait) TypeTree(firstParent) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index aea3d1ac9645..e61f7642cc71 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -39,7 +39,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) if (variance <= 0 && !isLegalPrefix(pre)) range(pre.bottomType, pre) else pre else if ((pre.termSymbol is Package) && !(thiscls is Package)) @@ -60,7 +60,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. if (tparams.head.eq(tparam)) return args.head match { case bounds: TypeBounds => - val v = currentVariance + val v = variance if (v > 0) bounds.hi else if (v < 0) bounds.lo else TypeArgRef(pre, cls.typeRef, idx) @@ -288,7 +288,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. * all (possibly applied) references to classes. */ def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[Type] = { - if (Config.newScheme) return parents.mapConserve(_.dealias) + if (Config.newScheme) return parents.mapConserve(_.dealias) // !@@@ track and eliminate usages? // println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG // A map consolidating all refinements arising from parent type parameters diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 00e5da305110..f9babab2f115 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4044,12 +4044,12 @@ object Types { abstract class DeepTypeMap(implicit ctx: Context) extends TypeMap { override def mapClassInfo(tp: ClassInfo) = { val prefix1 = this(tp.prefix) - val parentRefs1 = (tp.parentRefs mapConserve this).asInstanceOf[List[TypeRef]] + val parents1 = tp.parentsNEW mapConserve this val selfInfo1 = tp.selfInfo match { case selfInfo: Type => this(selfInfo) case selfInfo => selfInfo } - tp.derivedClassInfo(prefix1, parentRefs1, tp.decls, selfInfo1) + tp.derivedClassInfo(prefix1, parents1, tp.decls, selfInfo1) } } @@ -4280,7 +4280,7 @@ object Types { if (prefix.exists) tp.derivedTypeArgRef(prefix) else { val paramBounds = tp.underlying - approx(paramBounds.loBound, paramBounds.hiBound) + range(paramBounds.loBound, paramBounds.hiBound) } override protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation) = From 9b59150f5761812cc8aad74e4ef22001a40523fe Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 17:23:10 +0200 Subject: [PATCH 011/146] Fix debug output to make it more stable Avoid printing addresses and reduce junk. --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 5846c40091b1..06f889c66132 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -336,7 +336,7 @@ class Namer { typer: Typer => */ def enterSymbol(sym: Symbol)(implicit ctx: Context) = { if (sym.exists) { - typr.println(s"entered: $sym in ${ctx.owner} and ${ctx.effectiveScope}") + typr.println(s"entered: $sym in ${ctx.owner}") ctx.enter(sym) } sym diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 48dbf43af885..25702f45436c 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -83,6 +83,7 @@ object ProtoTypes { def isMatchedBy(tp1: Type)(implicit ctx: Context) = true def map(tm: TypeMap)(implicit ctx: Context): ProtoType = this def fold[T](x: T, ta: TypeAccumulator[T])(implicit ctx: Context): T = x + override def toString = getClass.toString } /** A class marking ignored prototypes that can be revealed by `deepenProto` */ From c3daec5e4e99e49c15741d02d606b226e2fde41a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 18:16:06 +0200 Subject: [PATCH 012/146] Fix Stackoverflow in asSeenFrom We had a stackoverfloa in asSeenFrom even under the old scheme, since there was a bad change involving checkRealizableBounds. --- compiler/src/dotty/tools/dotc/typer/Typer.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2851ae43979f..bd14f4a580ac 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1412,7 +1412,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) .withType(dummy.nonMemberTermRef) checkVariance(impl1) - if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls.appliedRef, cdef.namePos) + if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) + checkRealizableBounds(cls.thisType, cdef.namePos) // !@@@ adapt val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls) if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) From 4a6df0e924121fa149feac65274e57b13534dc2d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 18:53:02 +0200 Subject: [PATCH 013/146] Make newScheme non-final Otherwise we always need to a clean compile to update things. --- compiler/src/dotty/tools/dotc/config/Config.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 58d152de1f6d..fadf2e69e80f 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -175,5 +175,5 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - final val newScheme = true + val newScheme = false } From 0228613c83a67dec10ec8ed15c01b2ace1c0c8c0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 19:00:25 +0200 Subject: [PATCH 014/146] Partially revert change in TypeApplications#Reducer --- compiler/src/dotty/tools/dotc/core/TypeApplications.scala | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 7819e882e693..efd477e42dca 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -172,11 +172,9 @@ object TypeApplications { } def apply(t: Type) = t match { - case t @ TypeAlias(alias) => - applyArg(alias) match { - case arg1: TypeBounds => arg1 - case arg1 => t.derivedTypeAlias(arg1) - } + case t @ TypeAlias(p: TypeParamRef) if hasWildcardArg(p) && canReduceWildcard(p) => + available -= p.paramNum // @!!! needed in the future? + args(p.paramNum) case t @ AppliedType(tycon, args1) if tycon.typeSymbol.isClass => t.derivedAppliedType(apply(tycon), args1.mapConserve(applyArg)) case p: TypeParamRef if p.binder == tycon => From c65c10a785ad5ee9620f3c7b0137aa73cae31cb2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 16 Aug 2017 19:13:58 +0200 Subject: [PATCH 015/146] Use atVariance for new cases in TypeMaps and TypeAccumulators --- .../src/dotty/tools/dotc/core/Types.scala | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f9babab2f115..ad1e50ec5b5d 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3926,13 +3926,9 @@ object Types { | _: BoundType | NoPrefix => tp - case tp: AppliedType => // @!!! use atVariance - def mapArg(arg: Type, tparam: ParamInfo): Type = { - val saved = variance - variance *= tparam.paramVariance - try this(arg) - finally variance = saved - } + case tp: AppliedType => + def mapArg(arg: Type, tparam: ParamInfo): Type = + atVariance(variance * tparam.paramVariance)(this(arg)) derivedAppliedType(tp, this(tp.tycon), tp.args.zipWithConserve(tp.typeParams)(mapArg)) @@ -3974,11 +3970,7 @@ object Types { mapOverLambda case tp @ TypeArgRef(prefix, _, _) => - val saved = variance - variance = 0 - val prefix1 = this(prefix) - variance = saved - derivedTypeArgRef(tp, prefix1) + derivedTypeArgRef(tp, atVariance(0)(this(prefix))) case tp @ SuperType(thistp, supertp) => derivedSuperType(tp, this(thistp), this(supertp)) @@ -4359,13 +4351,9 @@ object Types { assert(tparams.isEmpty) x } - else { // @@!!! use atVariance + else { val tparam = tparams.head - val saved = variance - variance *= tparam.paramVariance - val acc = - try this(x, args.head) - finally variance = saved + val acc = atVariance(variance * tparam.paramVariance)(this(x, args.head)) foldArgs(acc, tparams.tail, args.tail) } foldArgs(this(x, tycon), tp.typeParams, args) From 83fb81254e96363a10ba25ee7786506384f03db3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Aug 2017 14:46:35 +0200 Subject: [PATCH 016/146] Fix bounds propagation The previous type parameter representation in terms of type members achieved bounds propagation by waiting until a type member was selected and then taking original bounds and refinements together as its info. This no longer works with explicit applications. Instead, we need to propagate bounds into wildcard arguments explicitly, when a type application is created. Also, fix argument computation in asSeenFrom --- .../tools/dotc/core/TypeApplications.scala | 43 ++++++++++++- .../src/dotty/tools/dotc/core/TypeOps.scala | 61 +++++++++---------- 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index efd477e42dca..9e5e57268d83 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -405,14 +405,51 @@ class TypeApplications(val self: Type) extends AnyVal { } case nil => t } + val stripped = self.stripTypeVar + val dealiased = stripped.safeDealias + + /** Normalize a TypeBounds argument. This involves (1) propagating bounds + * from the type parameters into the argument, (2) possibly choosing the argument's + * upper or lower bound according to variance. + * + * Bounds propagation works as follows: If the dealiased type constructor is a TypeRef + * `p.c`, + * - take the type paramater bounds of `c` as seen from `p`, + * - substitute concrete (non-bound) arguments for corresponding formal type parameters, + * - interpolate, so that any (F-bounded) type parameters in the resulting bounds are avoided. + * The resulting bounds are joined (via &) with corresponding type bound arguments. + */ def normalizeWildcardArg(arg: Type, tparam: TypeParamInfo): Type = arg match { case TypeBounds(lo, hi) => val v = tparam.paramVariance - if (v > 0) hi else if (v < 0) lo else arg + val avoidParams = new ApproximatingTypeMap { + variance = v + def apply(t: Type) = t match { + case t: TypeRef if typParams contains t.symbol => + val bounds = apply(t.info).bounds + range(bounds.lo, bounds.hi) + case _ => mapOver(t) + } + } + val pbounds = dealiased match { + case dealiased @ TypeRef(prefix, _) => + val (concreteArgs, concreteParams) = // @!!! optimize? + args.zip(typeParams.asInstanceOf[List[TypeSymbol]]) + .filter(!_._1.isInstanceOf[TypeBounds]) + .unzip + avoidParams( + tparam.paramInfo.asSeenFrom(prefix, tparam.asInstanceOf[TypeSymbol].owner) + .subst(concreteParams, concreteArgs)).orElse(TypeBounds.empty) + case _ => + TypeBounds.empty + } + //typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds") + if (v > 0) hi & pbounds.hiBound + else if (v < 0) lo | pbounds.loBound + else arg & pbounds case _ => arg } - val stripped = self.stripTypeVar - val dealiased = stripped.safeDealias + if (args.isEmpty || ctx.erasedTypes) self else dealiased match { case dealiased: HKTypeLambda => diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index e61f7642cc71..7881cd349d36 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -46,47 +46,44 @@ trait TypeOps { this: Context => // TODO: Make standalone object. toPrefix(pre.select(nme.PACKAGE), cls, thiscls) else toPrefix(pre.baseType(cls).normalizedPrefix, cls.owner, thiscls) - } + } } - def argForParam(pre: Type, tparam: Symbol): Type = { - val tparamCls = tparam.owner - pre.baseType(tparamCls) match { - case AppliedType(_, allArgs) => - var tparams = tparamCls.typeParams - var args = allArgs - var idx = 0 - while (tparams.nonEmpty && args.nonEmpty) { - if (tparams.head.eq(tparam)) - return args.head match { - case bounds: TypeBounds => - val v = variance - if (v > 0) bounds.hi - else if (v < 0) bounds.lo - else TypeArgRef(pre, cls.typeRef, idx) - case arg => arg - } - tparams = tparams.tail - args = args.tail - idx += 1 - } - throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") - case OrType(tp1, tp2) => argForParam(tp1, cls) | argForParam(tp2, cls) - case AndType(tp1, tp2) => argForParam(tp1, cls) & argForParam(tp2, cls) - case _ => tp + def argForParam(pre: Type, tparam: Symbol): Type = { + val tparamCls = tparam.owner + pre.baseType(tparamCls) match { + case AppliedType(_, allArgs) => + var tparams = tparamCls.typeParams + var args = allArgs + var idx = 0 + while (tparams.nonEmpty && args.nonEmpty) { + if (tparams.head.eq(tparam)) + return args.head match { + case bounds: TypeBounds => + val v = variance + if (v > 0) bounds.hi + else if (v < 0) bounds.lo + else TypeArgRef(pre, cls.typeRef, idx) + case arg => arg + } + tparams = tparams.tail + args = args.tail + idx += 1 + } + throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") + case OrType(tp1, tp2) => argForParam(tp1, cls) | argForParam(tp2, cls) + case AndType(tp1, tp2) => argForParam(tp1, cls) & argForParam(tp2, cls) + case _ => tp + } } - } /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG tp match { case tp: NamedType => val sym = tp.symbol if (sym.isStatic) tp - else { - val pre1 = atVariance(variance max 0)(this(tp.prefix)) - if (Config.newScheme && sym.is(TypeParam)) argForParam(pre1, sym) - else derivedSelect(tp, pre1) - } + else if (Config.newScheme && sym.is(TypeParam)) argForParam(pre, sym) + else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix))) case tp: ThisType => toPrefix(pre, cls, tp.cls) case _: BoundType | NoPrefix => From 6c5106e7ab406f9b6b4680246a07c9560739a41c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Aug 2017 16:38:14 +0200 Subject: [PATCH 017/146] Fix variance in avoidParams Need to avoid variance 0, as it leads to leaking ranges. --- compiler/src/dotty/tools/dotc/core/TypeApplications.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 9e5e57268d83..b57c2b16a634 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -15,7 +15,7 @@ import NameKinds._ import Flags._ import StdNames.tpnme import util.Positions.Position -import config.Printers.core +import config.Printers.{core, typr} import collection.mutable import dotty.tools.dotc.config.Config import java.util.NoSuchElementException @@ -423,7 +423,7 @@ class TypeApplications(val self: Type) extends AnyVal { case TypeBounds(lo, hi) => val v = tparam.paramVariance val avoidParams = new ApproximatingTypeMap { - variance = v + variance = if (v >= 0) 1 else -1 def apply(t: Type) = t match { case t: TypeRef if typParams contains t.symbol => val bounds = apply(t.info).bounds From 965a8e4d1a16253b849af00c37581508315eef0e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Aug 2017 16:38:45 +0200 Subject: [PATCH 018/146] Fix isSubArg Strange as it sounds, a TypeBounds can be a subtype of a single type. --- .../dotty/tools/dotc/core/TypeComparer.scala | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 7b6bb8e8c8ea..a647333ca60e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -925,10 +925,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tycon2: TypeRef => isMatchingApply(tp1) || { tycon2.info match { - case tycon2: TypeBounds => - compareLower(tycon2, tyconIsTypeRef = true) - case tycon2: ClassInfo => - val base = tp1.baseType(tycon2.cls) + case info2: TypeBounds => + compareLower(info2, tyconIsTypeRef = true) + case info2: ClassInfo => + val base = tp1.baseType(info2.cls) if (base.exists && base.ne(tp1)) isSubType(base, tp2) else fourthTry(tp1, tp2) case _ => @@ -976,8 +976,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2: TypeBounds => tp2.contains(tp1) case _ => - (v > 0 || isSubType(tp2, tp1)) && - (v < 0 || isSubType(tp1, tp2)) + tp1 match { + case TypeBounds(lo1, hi1) => + hi1 <:< tp2 && tp2 <:< lo1 // this can succeed in case tp2 bounds are bad + case _ => + (v > 0 || isSubType(tp2, tp1)) && + (v < 0 || isSubType(tp1, tp2)) + } } isSub(args1.head, args2.head) } && isSubArgs(args1.tail, args2.tail, tparams.tail) From d9476144ce6ec6b373efa2e3734b80e1b4c55e96 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Aug 2017 17:55:37 +0200 Subject: [PATCH 019/146] Avoid infinite expansion in normaizeWildcardArgs --- .../tools/dotc/core/TypeApplications.scala | 32 ++++++++++--------- tests/pos/boundspropagation.scala | 4 ++- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index b57c2b16a634..c9cc2e051c58 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -419,31 +419,32 @@ class TypeApplications(val self: Type) extends AnyVal { * - interpolate, so that any (F-bounded) type parameters in the resulting bounds are avoided. * The resulting bounds are joined (via &) with corresponding type bound arguments. */ - def normalizeWildcardArg(arg: Type, tparam: TypeParamInfo): Type = arg match { + def normalizeWildcardArg(typParams: List[TypeSymbol])(arg: Type, tparam: TypeSymbol): Type = arg match { case TypeBounds(lo, hi) => - val v = tparam.paramVariance - val avoidParams = new ApproximatingTypeMap { + def avoidParams(seen: Set[Symbol], v: Int): ApproximatingTypeMap = new ApproximatingTypeMap { variance = if (v >= 0) 1 else -1 def apply(t: Type) = t match { case t: TypeRef if typParams contains t.symbol => - val bounds = apply(t.info).bounds - range(bounds.lo, bounds.hi) + val lo = atVariance(-variance)(apply(t.info.loBound)) + val hi = + if (seen.contains(t.symbol)) t.topType + else avoidParams(seen + t.symbol, variance)(t.info.hiBound) + range(lo, hi) case _ => mapOver(t) } } + val v = tparam.paramVariance val pbounds = dealiased match { case dealiased @ TypeRef(prefix, _) => val (concreteArgs, concreteParams) = // @!!! optimize? - args.zip(typeParams.asInstanceOf[List[TypeSymbol]]) - .filter(!_._1.isInstanceOf[TypeBounds]) - .unzip - avoidParams( - tparam.paramInfo.asSeenFrom(prefix, tparam.asInstanceOf[TypeSymbol].owner) - .subst(concreteParams, concreteArgs)).orElse(TypeBounds.empty) + args.zip(typParams).filter(!_._1.isInstanceOf[TypeBounds]).unzip + avoidParams(Set(tparam), v)( + tparam.paramInfo.asSeenFrom(prefix, tparam.owner) + .subst(concreteParams, concreteArgs)) case _ => TypeBounds.empty } - //typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds") + typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds") if (v > 0) hi & pbounds.hiBound else if (v < 0) lo | pbounds.loBound else arg & pbounds @@ -500,9 +501,10 @@ class TypeApplications(val self: Type) extends AnyVal { case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => HKApply(self, args) case dealiased => - if (Config.newScheme) - AppliedType(self, args.zipWithConserve(typParams)(normalizeWildcardArg)) - else + if (Config.newScheme) { + val tparamSyms = typParams.asInstanceOf[List[TypeSymbol]] + AppliedType(self, args.zipWithConserve(tparamSyms)(normalizeWildcardArg(tparamSyms))) + } else matchParams(dealiased, typParams, args) } } diff --git a/tests/pos/boundspropagation.scala b/tests/pos/boundspropagation.scala index c2396c2c6ca3..8be3ff1cda9f 100644 --- a/tests/pos/boundspropagation.scala +++ b/tests/pos/boundspropagation.scala @@ -11,7 +11,9 @@ object test1 { } class Derived extends Base { def g(x: Any): Tree[N] = x match { - case y: Tree[_] => y // now succeeds in dotc + case y: Tree[_] => y.asInstanceOf + // without the cast: fails in scalac and new dotc + // used to succeed in dotc if type args are refinements } } } From abde37ead15e4defc002e4338ba433beae820547 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Aug 2017 18:29:53 +0200 Subject: [PATCH 020/146] Handle parameters from base classes of package objects Needed to compile i0239.scala correctly. --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 7881cd349d36..3ba2884ed4dd 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -73,7 +73,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object. throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") case OrType(tp1, tp2) => argForParam(tp1, cls) | argForParam(tp2, cls) case AndType(tp1, tp2) => argForParam(tp1, cls) & argForParam(tp2, cls) - case _ => tp + case _ => + if (pre.termSymbol is Package) argForParam(pre.select(nme.PACKAGE), tparam) + else throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") } } From ef086cedbe68c2d53230414cac915f52518e9f98 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 13:21:08 +0200 Subject: [PATCH 021/146] More fixes --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 11 +++++++---- compiler/src/dotty/tools/dotc/core/Types.scala | 2 ++ compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 9 ++++++++- tests/{pos => neg}/points.scala | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) rename tests/{pos => neg}/points.scala (59%) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 3ba2884ed4dd..fa20410cc788 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -71,11 +71,14 @@ trait TypeOps { this: Context => // TODO: Make standalone object. idx += 1 } throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") - case OrType(tp1, tp2) => argForParam(tp1, cls) | argForParam(tp2, cls) - case AndType(tp1, tp2) => argForParam(tp1, cls) & argForParam(tp2, cls) - case _ => + case OrType(tp1, tp2) => argForParam(tp1, tparam) | argForParam(tp2, tparam) + case AndType(tp1, tp2) => argForParam(tp1, tparam) & argForParam(tp2, tparam) + case base => if (pre.termSymbol is Package) argForParam(pre.select(nme.PACKAGE), tparam) - else throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") + else { + // throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated}, base = $base") // DEBUG + tp + } } } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ad1e50ec5b5d..a0cbb38ba477 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2182,6 +2182,8 @@ object Types { */ abstract case class SuperType(thistpe: Type, supertpe: Type) extends CachedProxyType with SingletonType { override def underlying(implicit ctx: Context) = supertpe + override def superType(implicit ctx: Context) = + thistpe.baseType(supertpe.typeSymbol) def derivedSuperType(thistpe: Type, supertpe: Type)(implicit ctx: Context) = if ((thistpe eq this.thistpe) && (supertpe eq this.supertpe)) this else SuperType(thistpe, supertpe) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index b52891ccddef..4d3ba7f02889 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -13,6 +13,7 @@ import scala.collection.{ mutable, immutable } import ast._ import Trees._ import TreeTransforms._ +import config.Printers.{checks, noPrinter} import util.DotClass import scala.util.{Try, Success, Failure} import config.{ScalaVersion, NoScalaVersion} @@ -652,7 +653,13 @@ object RefChecks { // 4. Check that every defined member with an `override` modifier overrides some other member. for (member <- clazz.info.decls) if (member.isAnyOverride && !(clazz.thisType.baseClasses exists (hasMatchingSym(_, member)))) { - // for (bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG + if (checks != noPrinter) { + for (bc <- clazz.info.baseClasses.tail) { + val sym = bc.info.decl(member.name).symbol + if (sym.exists) + checks.println(i"$bc has $sym: ${clazz.thisType.memberInfo(sym)}") + } + } val nonMatching = clazz.info.member(member.name).altsWith(alt => alt.owner != clazz) nonMatching match { diff --git a/tests/pos/points.scala b/tests/neg/points.scala similarity index 59% rename from tests/pos/points.scala rename to tests/neg/points.scala index db6104c883e5..e642fd737e76 100644 --- a/tests/pos/points.scala +++ b/tests/neg/points.scala @@ -3,6 +3,6 @@ class Point extends Comparable[Point] { } class ColoredPoint extends Point with Comparable[ColoredPoint] { - override def compareTo(other: ColoredPoint): Int = ??? + override def compareTo(other: ColoredPoint): Int = ??? // error: overridden method has different signature } From 357e2ae77ddb08c83987c17445029fcbaa12cb59 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 13:23:15 +0200 Subject: [PATCH 022/146] Fix #536 again Test case was extended and several fixes were necessary to make it pass. --- .../tools/dotc/core/ConstraintHandling.scala | 7 ++++- .../tools/dotc/core/TypeApplications.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 30 +++++++++---------- tests/pos/i536.scala | 9 ++++++ 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 06c56c9ef3a3..b3bbc6b1570b 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -312,7 +312,12 @@ trait ConstraintHandling { /** The current bounds of type parameter `param` */ final def bounds(param: TypeParamRef): TypeBounds = { val e = constraint.entry(param) - if (e.exists) e.bounds else param.binder.paramInfos(param.paramNum) + if (e.exists) e.bounds + else { + val pinfos = param.binder.paramInfos + if (pinfos != null) pinfos(param.paramNum) // pinfos == null happens in pos/i536.scala + else TypeBounds.empty + } } /** Add type lambda `tl`, possibly with type variables `tvars`, to current constraint diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index c9cc2e051c58..7b07260f680c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -447,7 +447,7 @@ class TypeApplications(val self: Type) extends AnyVal { typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds") if (v > 0) hi & pbounds.hiBound else if (v < 0) lo | pbounds.loBound - else arg & pbounds + else arg recoverable_& pbounds case _ => arg } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a0cbb38ba477..ceffd8162039 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -575,19 +575,7 @@ object Types { if (rinfo.isAlias) rinfo else if (pdenot.info.isAlias) pdenot.info else if (ctx.pendingMemberSearches.contains(name)) pdenot.info safe_& rinfo - else - 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 - // the special shortcut for Any in derivesFrom was as yet absent. To reproduce, - // remove the special treatment of Any in derivesFrom and compile - // sets.scala. - pdenot.info safe_& rinfo - } + else pdenot.info recoverable_& rinfo pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo) } else { pdenot & ( @@ -867,17 +855,29 @@ object Types { /** Safer version of `&`. * - * This version does not simplify the upper bound of the intersection of + * This version does not simplify the bounds of the intersection of * two TypeBounds. The simplification done by `&` requires subtyping checks * which may end up calling `&` again, in most cases this should be safe * but because of F-bounded types, this can result in an infinite loop * (which will be masked unless `-Yno-deep-subtypes` is enabled). + * pos/i536 demonstrates that the infinite loop can also invole lower bounds.wait */ def safe_& (that: Type)(implicit ctx: Context): Type = (this, that) match { - case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(lo1 | lo2, AndType(hi1, hi2)) + case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(OrType(lo1, lo2), AndType(hi1, hi2)) case _ => this & that } + /** `this & that`, but handle CyclicReferences by falling back to `safe_&`. + */ + def recoverable_&(that: Type)(implicit ctx: Context): Type = + try this & that + catch { + case ex: CyclicReference => this safe_& that + // A test case where this happens is tests/pos/i536.scala. + // The & causes a subtype check which calls baseTypeRef again with the same + // superclass. + } + def | (that: Type)(implicit ctx: Context): Type = track("|") { ctx.typeComparer.lub(this, that) } diff --git a/tests/pos/i536.scala b/tests/pos/i536.scala index db9fb9b389c4..f2b8f9ce6b28 100644 --- a/tests/pos/i536.scala +++ b/tests/pos/i536.scala @@ -1,3 +1,12 @@ +trait Comp[T] +trait Coll[T] +class C extends Comp[C] object Max { + def max[M <: Comp[_ >: M]](x: Coll[_ <: M]): M = ??? + def max[M](x: Coll[_ <: M], cmp: Object): M = ??? + val xs: Coll[C] = ??? + val m1 = max(xs) + val m2 = max(null) + java.util.Collections.max(null) } From f9520cb4b2e30dda494a525169aba2151f2c20fd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 13:47:57 +0200 Subject: [PATCH 023/146] Adapt ClassTypeParamCreationFlags to new scheme Re-fixes #938 --- compiler/src/dotty/tools/dotc/core/Flags.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 6ec87012cdc9..808242f71c4b 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc.core +package dotty.tools.dotc +package core import language.implicitConversions @@ -495,7 +496,8 @@ object Flags { final val SelfSymFlags = Private | Local | Deferred /** The flags of a class type parameter */ - final def ClassTypeParamCreationFlags = TypeParam | Deferred | Protected | Local + final val ClassTypeParamCreationFlags = + TypeParam | Deferred | (if (config.Config.newScheme) Private else Protected) | Local /** Flags that can apply to both a module val and a module class, except those that * are added at creation anyway From 842ac4b50465bdcadc99a1ca11e6de337cf3a74a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 15:24:09 +0200 Subject: [PATCH 024/146] Fix TypeArgRef and argForParam - Several fixes for TypeArgRef. - argForParam needs to follow owner chains like toPrefix does (see t119.scala) --- .../src/dotty/tools/dotc/core/TypeOps.scala | 35 +++++++++++++------ .../src/dotty/tools/dotc/core/Types.scala | 14 ++++---- .../tools/dotc/printing/PlainPrinter.scala | 2 +- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index fa20410cc788..4452269e83b5 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -49,9 +49,10 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } - def argForParam(pre: Type, tparam: Symbol): Type = { + def argForParam(pre: Type, cls: Symbol, tparam: Symbol): Type = { val tparamCls = tparam.owner - pre.baseType(tparamCls) match { + + def selectArg(base: Type): Type = base match { case AppliedType(_, allArgs) => var tparams = tparamCls.typeParams var args = allArgs @@ -63,7 +64,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. val v = variance if (v > 0) bounds.hi else if (v < 0) bounds.lo - else TypeArgRef(pre, cls.typeRef, idx) + else TypeArgRef(upper(pre), cls.typeRef, idx) case arg => arg } tparams = tparams.tail @@ -71,15 +72,27 @@ trait TypeOps { this: Context => // TODO: Make standalone object. idx += 1 } throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") - case OrType(tp1, tp2) => argForParam(tp1, tparam) | argForParam(tp2, tparam) - case AndType(tp1, tp2) => argForParam(tp1, tparam) & argForParam(tp2, tparam) + case OrType(base1, base2) => selectArg(base1) | selectArg(base2) + case AndType(base1, base2) => selectArg(base1) & selectArg(base2) case base => - if (pre.termSymbol is Package) argForParam(pre.select(nme.PACKAGE), tparam) - else { - // throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated}, base = $base") // DEBUG - tp - } + // throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated}, base = $base") // DEBUG + tp } + + def loop(pre: Type, cls: Symbol): Type = { + // println(i"argForParam $pre, $cls, $tparam") // DEBUG + val base = pre.baseType(cls) + if (pre.termSymbol is Package) + loop(pre.select(nme.PACKAGE), cls) + else if (cls eq tparamCls) + selectArg(base) + else if ((pre eq NoType) || (pre eq NoPrefix)|| (cls is PackageClass)) + tp + else + loop(base.normalizedPrefix, cls.owner) + } + + loop(pre, cls) } /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG @@ -87,7 +100,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. case tp: NamedType => val sym = tp.symbol if (sym.isStatic) tp - else if (Config.newScheme && sym.is(TypeParam)) argForParam(pre, sym) + else if (Config.newScheme && sym.is(TypeParam)) argForParam(pre, cls, sym) else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix))) case tp: ThisType => toPrefix(pre, cls, tp.cls) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index ceffd8162039..8c4e663a011c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3220,7 +3220,8 @@ object Types { /** A reference to wildcard argument `p.` * where `p: C[... _ ...]` */ - abstract case class TypeArgRef(prefix: Type, clsRef: TypeRef, idx: Int) extends CachedProxyType { + abstract case class TypeArgRef(prefix: Type, clsRef: TypeRef, idx: Int) extends CachedProxyType with ValueType { + assert(prefix.isInstanceOf[ValueType]) override def underlying(implicit ctx: Context): Type = prefix.baseType(clsRef.symbol).argInfos.apply(idx) def derivedTypeArgRef(prefix: Type)(implicit ctx: Context): Type = @@ -4271,11 +4272,12 @@ object Types { else tp.derivedAndOrType(tp1, tp2) override protected def derivedTypeArgRef(tp: TypeArgRef, prefix: Type): Type = - if (prefix.exists) tp.derivedTypeArgRef(prefix) - else { - val paramBounds = tp.underlying - range(paramBounds.loBound, paramBounds.hiBound) - } + if (isRange(prefix)) + tp.underlying match { + case TypeBounds(lo, hi) => range(atVariance(-variance)(reapply(lo)), reapply(hi)) + case _ => range(tp.bottomType, tp.topType) + } + else tp.derivedTypeArgRef(prefix) override protected def derivedAnnotatedType(tp: AnnotatedType, underlying: Type, annot: Annotation) = underlying match { diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index f4589bcc6d2a..dfb8838658b4 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -170,7 +170,7 @@ class PlainPrinter(_ctx: Context) extends Printer { val cls = clsRef.symbol val tparams = cls.typeParams val paramName = if (tparams.length > idx) nameString(tparams(idx)) else "" - toTextPrefix(prefix) ~ "" + toTextPrefix(prefix) ~ s"" case AndType(tp1, tp2) => changePrec(AndPrec) { toText(tp1) ~ " & " ~ toText(tp2) } case OrType(tp1, tp2) => From baf6bf5832a284480c89d9fa5237cc80ee9078c4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 18:44:29 +0200 Subject: [PATCH 025/146] Add capture conversion Needed to make i2250.scala compile --- .../dotty/tools/dotc/core/TypeComparer.scala | 45 ++++++++++++------- .../src/dotty/tools/dotc/core/Types.scala | 6 +++ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index a647333ca60e..b65b9e82b1d0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -659,12 +659,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tycon1: TypeParamRef => (tycon1 == tycon2 || canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) && - isSubArgs(args1, args2, tparams) + isSubArgs(args1, args2, tp1, tparams) case tycon1: TypeRef => tycon2.dealias match { case tycon2: TypeRef if tycon1.symbol == tycon2.symbol => isSubType(tycon1.prefix, tycon2.prefix) && - isSubArgs(args1, args2, tparams) + isSubArgs(args1, args2, tp1, tparams) case _ => false } @@ -786,7 +786,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case param1: TypeParamRef => def canInstantiate = tp2 match { case AnyAppliedType(tycon2, args2) => - tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams) + tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tp1, tycon2.typeParams) case _ => false } @@ -813,12 +813,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tycon1: TypeParamRef => (tycon1 == tycon2 || canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) && - isSubArgs(args1, args2, tparams) + isSubArgs(args1, args2, tp1, tparams) case tycon1: TypeRef => tycon2.dealias match { case tycon2: TypeRef if tycon1.symbol == tycon2.symbol => isSubType(tycon1.prefix, tycon2.prefix) && - isSubArgs(args1, args2, tparams) + isSubArgs(args1, args2, tp1, tparams) case _ => false } @@ -951,7 +951,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case param1: TypeParamRef => def canInstantiate = tp2 match { case AnyAppliedType(tycon2, args2) => - tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tycon2.typeParams) + tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tp1, tycon2.typeParams) case _ => false } @@ -968,24 +968,35 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** Subtype test for corresponding arguments in `args1`, `args2` according to * variances in type parameters `tparams`. */ - def isSubArgs(args1: List[Type], args2: List[Type], tparams: List[ParamInfo]): Boolean = + def isSubArgs(args1: List[Type], args2: List[Type], tp1: Type, tparams: List[ParamInfo]): Boolean = if (args1.isEmpty) args2.isEmpty else args2.nonEmpty && { - val v = tparams.head.paramVariance - def isSub(tp1: Type, tp2: Type) = tp2 match { - case tp2: TypeBounds => - tp2.contains(tp1) + val tparam = tparams.head + val v = tparam.paramVariance + + def compareCaptured(arg1: Type, arg2: Type) = arg1 match { + case arg1: TypeBounds => + val captured = TypeArgRef.fromParam(SkolemType(tp1), tparam.asInstanceOf[TypeSymbol]) + isSubType(captured, arg2) case _ => - tp1 match { - case TypeBounds(lo1, hi1) => - hi1 <:< tp2 && tp2 <:< lo1 // this can succeed in case tp2 bounds are bad + false + } + + def isSub(arg1: Type, arg2: Type) = arg2 match { + case arg2: TypeBounds => + arg2.contains(arg1) || compareCaptured(arg1, arg2) + case _ => + arg1 match { + case arg1: TypeBounds => + compareCaptured(arg1, arg2) case _ => - (v > 0 || isSubType(tp2, tp1)) && - (v < 0 || isSubType(tp1, tp2)) + (v > 0 || isSubType(arg2, arg1)) && + (v < 0 || isSubType(arg1, arg2)) } } + isSub(args1.head, args2.head) - } && isSubArgs(args1.tail, args2.tail, tparams.tail) + } && isSubArgs(args1.tail, args2.tail, tp1, tparams.tail) /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where * - `B` derives from one of the class symbols of `tp2`, diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8c4e663a011c..7136ab838ef9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3222,6 +3222,8 @@ object Types { */ abstract case class TypeArgRef(prefix: Type, clsRef: TypeRef, idx: Int) extends CachedProxyType with ValueType { assert(prefix.isInstanceOf[ValueType]) + assert(idx >= 0) + override def underlying(implicit ctx: Context): Type = prefix.baseType(clsRef.symbol).argInfos.apply(idx) def derivedTypeArgRef(prefix: Type)(implicit ctx: Context): Type = @@ -3234,6 +3236,10 @@ object Types { object TypeArgRef { def apply(prefix: Type, clsRef: TypeRef, idx: Int)(implicit ctx: Context) = unique(new CachedTypeArgRef(prefix, clsRef, idx)) + def fromParam(prefix: Type, tparam: TypeSymbol)(implicit ctx: Context) = { + val cls = tparam.owner + apply(prefix, cls.typeRef, cls.typeParams.indexOf(tparam)) + } } // ----- BoundTypes: ParamRef, RecThis ---------------------------------------- From 90fd77f6e8399345b98d1a9e1fa76de6388dc64d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 19:17:48 +0200 Subject: [PATCH 026/146] Fix ExpandSAMs Can't rely any ore that refinements are stripped away in normalizeClassRef --- compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 29e9d3813abf..76ba7245d6c8 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -41,10 +41,10 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => checkRefinements(tpe, fn.pos) tree case tpe => - checkRefinements(tpe, fn.pos) - val Seq(samDenot) = tpe.abstractTermMembers.filter(!_.symbol.isSuperAccessor) + val tpe1 = checkRefinements(tpe, fn.pos) + val Seq(samDenot) = tpe1.abstractTermMembers.filter(!_.symbol.isSuperAccessor) cpy.Block(tree)(stats, - AnonClass(tpe :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil)) + AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil)) } case _ => tree @@ -88,12 +88,13 @@ class ExpandSAMs extends MiniPhaseTransform { thisTransformer => cpy.Block(tree)(List(applyDef, isDefinedAtDef), anonCls) } - private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Unit = tpe match { + private def checkRefinements(tpe: Type, pos: Position)(implicit ctx: Context): Type = tpe match { case RefinedType(parent, name, _) => if (name.isTermName && tpe.member(name).symbol.ownersIterator.isEmpty) // if member defined in the refinement ctx.error("Lambda does not define " + name, pos) checkRefinements(parent, pos) case _ => + tpe } } From 0e4a3ea39a2df5ab7ebaf551c86a5944acb80975 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Aug 2017 21:01:19 +0200 Subject: [PATCH 027/146] Fix implicit scope computation --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 575bbc8d970e..5bb2e95e0720 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -438,11 +438,14 @@ trait ImplicitRunInfo { self: RunInfo => else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } - def addParentScope(parent: Type): Unit = { - iscopeRefs(parent.typeConstructor) foreach addRef - for (param <- parent.typeParamSymbols) - comps ++= iscopeRefs(tp.member(param.name).info) - } + def addParentScope(parent: Type): Unit = + if (Config.newScheme) + iscopeRefs(parent) foreach addRef + else { + iscopeRefs(parent.typeConstructor) foreach addRef + for (param <- parent.typeParamSymbols) + comps ++= iscopeRefs(tp.member(param.name).info) + } val companion = cls.companionModule if (companion.exists) addRef(companion.valRef) cls.classParentsNEW foreach addParentScope From d71dc4b013e7b6b435721782f7ad1cf83f339d5b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 19 Aug 2017 11:08:00 +0200 Subject: [PATCH 028/146] Refine typeMismatchMsg Without the tweak, neg/i1181c.scala gives the non-sensical message `type mismatch: found: Foo[Int, Int], expected: Any`. --- .../tools/dotc/typer/ErrorReporting.scala | 7 ++++++- tests/neg/i1181c.scala | 21 +++++++++++++++++++ tests/pos/i1181c.scala | 12 ++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 tests/neg/i1181c.scala diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index c48510d91b34..3b087dd08ae3 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -134,6 +134,9 @@ object ErrorReporting { def typeMismatchMsg(found: Type, expected: Type, postScript: String = "") = { // replace constrained TypeParamRefs and their typevars by their bounds where possible + // the idea is that if the bounds are also not-subtypes of each other to report + // the type mismatch on the bounds instead of the original TypeParamRefs, since + // these are usually easier to analyze. object reported extends TypeMap { def setVariance(v: Int) = variance = v val constraint = ctx.typerState.constraint @@ -154,7 +157,9 @@ object ErrorReporting { val found1 = reported(found) reported.setVariance(-1) val expected1 = reported(expected) - TypeMismatch(found1, expected1, whyNoMatchStr(found, expected), postScript) + val (found2, expected2) = + if (found1 <:< expected1) (found, expected) else (found1, expected1) + TypeMismatch(found2, expected2, whyNoMatchStr(found, expected), postScript) } /** Format `raw` implicitNotFound argument, replacing all diff --git a/tests/neg/i1181c.scala b/tests/neg/i1181c.scala new file mode 100644 index 000000000000..281640d95275 --- /dev/null +++ b/tests/neg/i1181c.scala @@ -0,0 +1,21 @@ +// This program compiles with Dotty using refined types for application, but +// does not compile with native applications. The reason is that in previous +// Dotty the parameter reference to the lambda [X, Y] => Foo[X, Y] was a TypeRef +// which could be selected for partial application. But now the type lambda gets +// substituted directly, which prevents that conversion. The program compiles +// if the type lambda is replaced by a type alias (see pos/i1181c.scala). +class Foo[A] + +trait Bar[DD[_,_]] { + val x: DD[Int, Int] +} + +object Test { + type F[X, Y] = Foo[X] + + trait Baz extends Bar[[X,Y] => Foo[X]] { + def foo[M[_,_]](x: M[Int, Int]) = x + + foo(x) // error: found: Foo[Int](Baz.this.x) required: M[Int, Int] + } +} diff --git a/tests/pos/i1181c.scala b/tests/pos/i1181c.scala index 58bd9976645b..c46b34eb3bf3 100644 --- a/tests/pos/i1181c.scala +++ b/tests/pos/i1181c.scala @@ -1,11 +1,17 @@ +// See also neg/i1181c.scala for a variant which doe not compile class Foo[A] trait Bar[DD[_,_]] { val x: DD[Int, Int] } -trait Baz extends Bar[[X,Y] => Foo[X]] { - def foo[M[_,_]](x: M[Int, Int]) = x +object Test { + type F[X, Y] = Foo[X] - foo(x) + type LAMBDA[X,Y] = Foo[X] + trait Baz extends Bar[LAMBDA] { + def foo[M[_,_]](x: M[Int, Int]) = x + + foo(x) // error: found: Foo[Int](Baz.this.x) required: M[Int, Int] + } } From 850e5d93f48a1530de32cc6b9834ff715b3b0104 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 19 Aug 2017 15:00:49 +0200 Subject: [PATCH 029/146] Generalize argForParam Make argForParam part of derivedSelect. This not only necessary for asSeenFrom but also for other transformatuons that change ThisTypes to something that can instantiate a type parameters. An example is the tree type map in the inliner. The change fixes i1891.scala. --- .../src/dotty/tools/dotc/core/TypeOps.scala | 49 +-------------- .../src/dotty/tools/dotc/core/Types.scala | 61 ++++++++++++++++--- .../dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 4452269e83b5..bf80e7cab401 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -49,58 +49,13 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } - def argForParam(pre: Type, cls: Symbol, tparam: Symbol): Type = { - val tparamCls = tparam.owner - - def selectArg(base: Type): Type = base match { - case AppliedType(_, allArgs) => - var tparams = tparamCls.typeParams - var args = allArgs - var idx = 0 - while (tparams.nonEmpty && args.nonEmpty) { - if (tparams.head.eq(tparam)) - return args.head match { - case bounds: TypeBounds => - val v = variance - if (v > 0) bounds.hi - else if (v < 0) bounds.lo - else TypeArgRef(upper(pre), cls.typeRef, idx) - case arg => arg - } - tparams = tparams.tail - args = args.tail - idx += 1 - } - throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated} ") - case OrType(base1, base2) => selectArg(base1) | selectArg(base2) - case AndType(base1, base2) => selectArg(base1) & selectArg(base2) - case base => - // throw new AssertionError(ex"$pre contains no matching argument for ${tparam.showLocated}, base = $base") // DEBUG - tp - } - - def loop(pre: Type, cls: Symbol): Type = { - // println(i"argForParam $pre, $cls, $tparam") // DEBUG - val base = pre.baseType(cls) - if (pre.termSymbol is Package) - loop(pre.select(nme.PACKAGE), cls) - else if (cls eq tparamCls) - selectArg(base) - else if ((pre eq NoType) || (pre eq NoPrefix)|| (cls is PackageClass)) - tp - else - loop(base.normalizedPrefix, cls.owner) - } - - loop(pre, cls) - } - /*>|>*/ ctx.conditionalTraceIndented(TypeOps.track, s"asSeen ${tp.show} from (${pre.show}, ${cls.show})", show = true) /*<|<*/ { // !!! DEBUG + // All cases except for ThisType are the same as in Map. Inlined for performance + // TODO: generalize the inlining trick? tp match { case tp: NamedType => val sym = tp.symbol if (sym.isStatic) tp - else if (Config.newScheme && sym.is(TypeParam)) argForParam(pre, cls, sym) else derivedSelect(tp, atVariance(variance max 0)(this(tp.prefix))) case tp: ThisType => toPrefix(pre, cls, tp.cls) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7136ab838ef9..c5732f1e684a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1814,6 +1814,43 @@ 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`. + */ + def argForParam(pre: Type)(implicit ctx: Context): Type = { + val tparam = symbol + val cls = tparam.owner + val base = pre.baseType(cls) + base match { + case AppliedType(_, allArgs) => + var tparams = cls.typeParams + var args = allArgs + var idx = 0 + while (tparams.nonEmpty && args.nonEmpty) { + if (tparams.head.eq(tparam)) + return args.head match { + case _: TypeBounds => TypeArgRef(pre, cls.typeRef, idx) + case arg => arg + } + tparams = tparams.tail + args = args.tail + idx += 1 + } + NoType + case OrType(base1, base2) => argForParam(base1) | argForParam(base2) + case AndType(base1, base2) => argForParam(base1) & argForParam(base2) + case _ => + if (pre.termSymbol is Package) argForParam(pre.select(nme.PACKAGE)) + else if (pre.isBottomType) pre.bottomType + else NoType + } + } + + def isClassParam(implicit ctx: Context) = + Config.newScheme && symbol.is(TypeParam) && symbol.owner.isClass + /** A selection of the same kind, but with potentially a different prefix. * The following normalizations are performed for type selections T#A: * @@ -1830,7 +1867,7 @@ object Types { if (prefix eq this.prefix) this else if (prefix.isBottomType) prefix else if (isType) { - val res = prefix.lookupRefined(name) + val res = if (isClassParam) argForParam(prefix) else prefix.lookupRefined(name) if (res.exists) res else if (Config.splitProjections) prefix match { @@ -3882,7 +3919,13 @@ object Types { def apply(tp: Type): Type protected def derivedSelect(tp: NamedType, pre: Type): Type = - tp.derivedSelect(pre) + tp.derivedSelect(pre) match { + case tp: TypeArgRef if variance != 0 => + val tp1 = tp.underlying + if (variance > 0) tp1.hiBound else tp1.loBound + case tp => + tp + } protected def derivedRefinedType(tp: RefinedType, parent: Type, info: Type): Type = tp.derivedRefinedType(parent, tp.refinedName, info) protected def derivedRecType(tp: RecType, parent: Type): Type = @@ -4094,7 +4137,7 @@ object Types { * The possible cases are listed inline in the code. Return `default` if no widening is * possible. */ - def tryWiden(tp: NamedType, pre: Type)(default: => Type): Type = + def tryWiden(tp: NamedType, pre: Type): Type = pre.member(tp.name) match { case d: SingleDenotation => d.info match { @@ -4111,9 +4154,9 @@ object Types { // hence we can replace with y.type under all variances reapply(info) case _ => - default + NoType } - case _ => default + case _ => NoType } /** Derived selection. @@ -4123,9 +4166,13 @@ object Types { if (pre eq tp.prefix) tp else pre match { case Range(preLo, preHi) => - tryWiden(tp, preHi)(range(tp.derivedSelect(preLo), tp.derivedSelect(preHi))) + val forwarded = + if (tp.isClassParam) tp.argForParam(preHi) + else tryWiden(tp, preHi) + forwarded.orElse( + range(super.derivedSelect(tp, preLo), super.derivedSelect(tp, preHi))) case _ => - tp.derivedSelect(pre) + super.derivedSelect(tp, pre) } override protected def derivedRefinedType(tp: RefinedType, parent: Type, info: Type) = diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 4485e6ff6e52..fa111fb98002 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -120,7 +120,7 @@ trait TypeAssigner { override def derivedSelect(tp: NamedType, pre: Type) = if (pre eq tp.prefix) tp - else tryWiden(tp, tp.prefix) { + else tryWiden(tp, tp.prefix).orElse { if (tp.isTerm && variance > 0 && !pre.isInstanceOf[SingletonType]) apply(tp.info.widenExpr) else if (upper(pre).member(tp.name).exists) From 584eaefc1d9efc792ae666f07823ad16bc8b6a41 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 20 Aug 2017 10:50:34 +0200 Subject: [PATCH 030/146] Check that class type parameters are only referenced via their this-types Prviously, class type parameters were public, and thus could be referenced with any prefix. Now they are private local. The check ensures that transforms respect that invariant and that we know as soon as possible if they don't. --- compiler/src/dotty/tools/dotc/config/Config.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index fadf2e69e80f..b0767e46d08b 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -79,7 +79,7 @@ object Config { final val traceDeepSubTypeRecursions = false /** When explaining subtypes and this flag is set, also show the classes of the compared types. */ - final val verboseExplainSubtype = true + final val verboseExplainSubtype = false /** If this flag is set, take the fast path when comparing same-named type-aliases and types */ final val fastPathForRefinedSubtype = true @@ -113,6 +113,11 @@ object Config { */ final val checkTypeRefCycles = false + /** If this flag is set, it is checked that class type parameters are + * only references with NoPrefix or ThisTypes as prefixes. + */ + final val checkTypeParamRefs = true + /** The recursion depth for showing a summarized string */ final val summarizeDepth = 2 From dcec2da0cb78d5de1d91f6eb45b920b6a9a81bf2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 20 Aug 2017 10:50:43 +0200 Subject: [PATCH 031/146] Check that class type parameters are only referenced via their this-types Previously, class type parameters were public, and thus could be referenced with any prefix. Now they are private local. The check ensures that transforms respect that invariant and that we know as soon as possible if they don't. The flag is normally disabled, because there are still some legitimate cases that trigger it. Need to investigate these further. --- compiler/src/dotty/tools/dotc/config/Config.scala | 6 ++++-- compiler/src/dotty/tools/dotc/core/Flags.scala | 3 +++ compiler/src/dotty/tools/dotc/core/Types.scala | 12 +++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index b0767e46d08b..b578681f459e 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -114,9 +114,11 @@ object Config { final val checkTypeRefCycles = false /** If this flag is set, it is checked that class type parameters are - * only references with NoPrefix or ThisTypes as prefixes. + * only references with NoPrefix or ThisTypes as prefixes. This option + * is usally disabled, because there are still some legitimate cases where + * this can arise (e.g. for pos/Map.scala, in LambdaType.integrate). */ - final val checkTypeParamRefs = true + final val checkTypeParamRefs = false /** The recursion depth for showing a summarized string */ final val summarizeDepth = 2 diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 808242f71c4b..e1a5aed2afcf 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -593,6 +593,9 @@ object Flags { /** Is valid forever */ final val ValidForever = Package | Permanent | Scala2ExistentialCommon + /** A type parameter of a class or trait (works only under Config.newScheme) */ + final val ClassTypeParam = allOf(TypeParam, Private) + /** Is a default parameter in Scala 2*/ final val DefaultParameter = allOf(Param, DefaultParameterized) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c5732f1e684a..868e07755d3d 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1584,7 +1584,7 @@ object Types { } /** Hook for adding debug check code when denotations are assigned */ - final def checkDenot()(implicit ctx: Context) = + final def checkDenot()(implicit ctx: Context) = { if (Config.checkTypeRefCycles) lastDenotation match { case d: SingleDenotation => @@ -1596,6 +1596,16 @@ object Types { } case _ => } + if (Config.checkTypeParamRefs && Config.newScheme) + 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 = { From 588f1dcdc4ec2854133e651a06a2c7217b7bcc34 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 20 Aug 2017 11:11:45 +0200 Subject: [PATCH 032/146] Fix illegal select in VCInlineMethods VCInline methods selected a type parameter from a non-this prefix directly. This is no longer allowed, as type parameters are now private. Need to do a asSeenFrom instead. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +++- .../dotty/tools/dotc/transform/VCInlineMethods.scala | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 488aff9f8f1c..5065b87f16ca 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -698,8 +698,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { */ def select(sym: Symbol)(implicit ctx: Context): Select = { val tp = - if (sym.isType) + if (sym.isType) { + assert(!sym.is(TypeParam)) TypeRef(tree.tpe, sym.name.asTypeName) + } else TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe)) diff --git a/compiler/src/dotty/tools/dotc/transform/VCInlineMethods.scala b/compiler/src/dotty/tools/dotc/transform/VCInlineMethods.scala index af950a209f67..146d30697bae 100644 --- a/compiler/src/dotty/tools/dotc/transform/VCInlineMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/VCInlineMethods.scala @@ -23,11 +23,12 @@ import collection.mutable.ListBuffer * type parameter, then we can rewrite: * e.foo[X, Y, ...](args) * as: - * V.foo$extension[X, Y, ..., e.A, e.B, ...](e)(args) + * V.foo$extension[X, Y, ..., A', B', ...](e)(args) + * where A', B', ... are the class type parameters A, B, ... as seen from `e`. * Otherwise, we need to evaluate e first: * { * val ev = e - * V.foo$extension[X, Y, ..., ev.A, ev.B, ...](ev)(args) + * V.foo$extension[X, Y, ..., A', B', ...](ev)(args) * } * * This phase needs to be placed after phases which may introduce calls to @@ -63,12 +64,14 @@ class VCInlineMethods extends MiniPhaseTransform with IdentityDenotTransformer { rewire(qual, mtArgs2, mArgss) case sel @ Select(qual, _) => val origMeth = sel.symbol - val ctParams = origMeth.enclosingClass.typeParams + val origCls = origMeth.enclosingClass + val ctParams = origCls.typeParams val extensionMeth = extensionMethod(origMeth) if (!ctParams.isEmpty) { evalOnce(qual) { ev => - val ctArgs = ctParams map (ev.select(_)) + val ctArgs = ctParams.map(tparam => + TypeTree(tparam.typeRef.asSeenFrom(ev.tpe, origCls))) ref(extensionMeth) .appliedToTypeTrees(mtArgs ++ ctArgs) .appliedTo(ev) From 596fa17e9603e7d873821b0a7fa2f544a3bc62cd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Aug 2017 09:28:40 +0200 Subject: [PATCH 033/146] Fix classBound We need to take type parameters of the abstracted-over class into account. --- .../tools/dotc/core/TypeApplications.scala | 7 +------ .../dotty/tools/dotc/typer/TypeAssigner.scala | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 7b07260f680c..682984b26756 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -208,12 +208,7 @@ class TypeApplications(val self: Type) extends AnyVal { * For a typeref referring to a Lambda class, the type parameters of * its right hand side or upper bound. * For a refinement type, the type parameters of its parent, dropping - * any type parameter that is-rebound by the refinement. "Re-bind" means: - * The refinement contains a TypeAlias for the type parameter, or - * it introduces bounds for the type parameter, and we are not in the - * special case of a type Lambda, where a LambdaTrait gets refined - * with the bounds on its hk args. See `LambdaAbstract`, where these - * types get introduced, and see `isBoundedLambda` below for the test. + * any type parameter that is-rebound by the refinement. */ final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ { self match { diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index fa111fb98002..291b23668bb1 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -39,14 +39,19 @@ trait TypeAssigner { } } - /** Given a class info, the intersection of its parents, refined by all - * non-private fields, methods, and type members. + /** An abstraction of a class info, consisting of + * - the intersection of its parents, + * - refined by all non-private fields, methods, and type members, + * - abstracted over all type parameters (into a type lambda) + * - where all references to `this` of the class are closed over in a RecType. */ def classBound(info: ClassInfo)(implicit ctx: Context): Type = { + val cls = info.cls val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _)) + def addRefinement(parent: Type, decl: Symbol) = { val inherited = - parentType.findMember(decl.name, info.cls.thisType, excluded = Private) + parentType.findMember(decl.name, cls.thisType, excluded = Private) .suchThat(decl.matches(_)) val inheritedInfo = inherited.info if (inheritedInfo.exists && decl.info <:< inheritedInfo && !(inheritedInfo <:< decl.info)) { @@ -57,10 +62,16 @@ trait TypeAssigner { else parent } + + def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, RecThis(rt))) + val refinableDecls = info.decls.filter( sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor)) val raw = (parentType /: refinableDecls)(addRefinement) - RecType.closeOver(rt => raw.substThis(info.cls, RecThis(rt))) + HKTypeLambda.fromParams(cls.typeParams, raw) match { + case tl: HKTypeLambda => tl.derivedLambdaType(resType = close(tl.resType)) + case tp => close(tp) + } } /** An upper approximation of the given type `tp` that does not refer to any symbol in `symsToAvoid`. From 5bfa1536287c799b9d2278e5a0d06ad3fd9db902 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Aug 2017 14:57:20 +0200 Subject: [PATCH 034/146] Fix t8280 There is a curious discrepancy between the two dotty versions here. After looking at it some more, it seems the new dotty version is the correct one. --- tests/run/t8280.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run/t8280.scala b/tests/run/t8280.scala index 5fcbad0a3ab1..7578e0417ff4 100644 --- a/tests/run/t8280.scala +++ b/tests/run/t8280.scala @@ -83,7 +83,8 @@ object Moop3 { implicit val f1: ImplicitConverter[Int, String] = _ => "Int" implicit val f2: ImplicitConverter[Long, String] = _ => "Long" - println(5: String) + println((5: Int): String) + // println(5: String) // error: ambiguity, since both f1 and f2 are applicable to 5. } } From b9f3084205bc9fcbd2a5181d3f0e539e2a20253a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Aug 2017 15:44:27 +0200 Subject: [PATCH 035/146] Adapt flip in Applications to new scheme We need a more robust way to turn around parameter variance for overloading resolution. --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index abad8e78a6df..218ec3f704a3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1146,12 +1146,18 @@ trait Applications extends Compatibility { self: Typer with Dynamic => else { val flip = new TypeMap { def apply(t: Type) = t match { - case t: TypeAlias if variance > 0 && t.variance < 0 => t.derivedTypeAlias(t.alias, 1) + case t @ TypeAlias(alias) if variance > 0 && t.variance < 0 && !Config.newScheme => + t.derivedTypeAlias(defn.FunctionOf(alias :: Nil, defn.UnitType)) case t: TypeBounds => t + case t @ AppliedType(tycon, args) if Config.newScheme => + def mapArg(arg: Type, tparam: TypeParamInfo) = + if (variance > 0 && tparam.paramVariance < 0) defn.FunctionOf(arg :: Nil, defn.UnitType) + else arg + mapOver(t.derivedAppliedType(tycon, args.zipWithConserve(tycon.typeParams)(mapArg))) case _ => mapOver(t) } } - isCompatible(flip(tp1), flip(tp2)) + (flip(tp1) relaxed_<:< flip(tp2)) || viewExists(tp1, tp2) } /** Drop any implicit parameter section */ From 756238e0f626506fefe42339b08c79642d6cef64 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Aug 2017 17:51:32 +0200 Subject: [PATCH 036/146] Fix type of outer accessor Previously, we just used the typeRef, but with applied types we need a much more complicated computation. --- .../tools/dotc/transform/ExplicitOuter.scala | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index cb10173dd554..284a8b3649f5 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -155,9 +155,28 @@ object ExplicitOuter { private def newOuterAccessors(cls: ClassSymbol)(implicit ctx: Context) = newOuterAccessor(cls, cls) :: (if (cls is Trait) Nil else newOuterParamAccessor(cls) :: Nil) - /** A new outer accessor or param accessor */ + /** A new outer accessor or param accessor. + * @param owner The class where the outer accessor is located + * @param cls The class relative to which the outer is computed (can be a base class of owner) + * @param name The name of the outer access + * @param flags The flags of the outer accessor + * + * The type of the outer accessor is computed as follows: + * Let O[X1, .., Xn] be the class eclosing `cls`. + * - if owner == cls, O[X1, ..., Xn] + * - otherwise, if the class P enclosing `owner` derives from O, the + * base type of P.this of class O + * - otherwise O[_, ..., _] + */ private def newOuterSym(owner: ClassSymbol, cls: ClassSymbol, name: TermName, flags: FlagSet)(implicit ctx: Context) = { - val target = cls.owner.enclosingClass.appliedRef + val outerThis = owner.owner.enclosingClass.thisType + val outerCls = cls.owner.enclosingClass + val target = + if (owner == cls) + outerCls.appliedRef + else + outerThis.baseType(outerCls).orElse( + outerCls.typeRef.appliedTo(outerCls.typeParams.map(_ => TypeBounds.empty))) val info = if (flags.is(Method)) ExprType(target) else target ctx.withPhaseNoEarlier(ctx.explicitOuterPhase.next) // outer accessors are entered at explicitOuter + 1, should not be defined before. .newSymbol(owner, name, Synthetic | flags, info, coord = cls.coord) From 471e62b6b2bbc3812f5fe5c157b790b3f37ebe81 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Aug 2017 13:22:28 +0200 Subject: [PATCH 037/146] Fix computation of implicit scope 3 changes: - handle LazyRef correctly in wildApprox - compute correct parents - drop buggy special case for AppliedType in liftToClasses --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 11 ++--------- compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 -- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 5bb2e95e0720..6f75dd9df1b7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -385,14 +385,7 @@ trait ImplicitRunInfo { self: RunInfo => (lead /: tp.classSymbols)(joinClass) case tp: TypeVar => apply(tp.underlying) - case tp: AppliedType => - def applyArg(arg: Type) = arg match { - case TypeBounds(lo, hi) => AndType.make(lo, hi) - case _: WildcardType => defn.AnyType - case _ => arg - } - (apply(tp.tycon) /: tp.args)((tc, arg) => AndType.make(tc, applyArg(arg))) - case tp: HKApply => + case tp: HKApply => // @!!! needed? def applyArg(arg: Type) = arg match { case TypeBounds(lo, hi) => AndType.make(lo, hi) case _: WildcardType => defn.AnyType @@ -440,7 +433,7 @@ trait ImplicitRunInfo { self: RunInfo => } def addParentScope(parent: Type): Unit = if (Config.newScheme) - iscopeRefs(parent) foreach addRef + iscopeRefs(tp.baseType(parent.typeSymbol)) foreach addRef else { iscopeRefs(parent.typeConstructor) foreach addRef for (param <- parent.typeParamSymbols) diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 25702f45436c..7c1950625e1e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -534,8 +534,6 @@ object ProtoTypes { tp.derivedOrType(tp1a, tp2a) } approxOr - case tp: LazyRef => - WildcardType case tp: SelectionProto => tp.derivedSelectionProto(tp.name, wildApprox(tp.memberProto, theMap, seen), NoViewsAllowed) case tp: ViewProto => From 2b10447bb38af141e38eba5ae00208645e3619c5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 22 Aug 2017 13:24:14 +0200 Subject: [PATCH 038/146] Fix problem in isSubArg Needed to correctly flag errors in neg/skolemize.scala. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b65b9e82b1d0..63017b62d7dc 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -974,15 +974,15 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val tparam = tparams.head val v = tparam.paramVariance - def compareCaptured(arg1: Type, arg2: Type) = arg1 match { + def compareCaptured(arg1: Type, arg2: Type): Boolean = arg1 match { case arg1: TypeBounds => val captured = TypeArgRef.fromParam(SkolemType(tp1), tparam.asInstanceOf[TypeSymbol]) - isSubType(captured, arg2) + isSubArg(captured, arg2) case _ => false } - def isSub(arg1: Type, arg2: Type) = arg2 match { + def isSubArg(arg1: Type, arg2: Type): Boolean = arg2 match { case arg2: TypeBounds => arg2.contains(arg1) || compareCaptured(arg1, arg2) case _ => @@ -995,7 +995,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } } - isSub(args1.head, args2.head) + isSubArg(args1.head, args2.head) } && isSubArgs(args1.tail, args2.tail, tp1, tparams.tail) /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where From 27dbeef8a6cd69953920ac2b844042c4d698bc3d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 09:54:24 +0200 Subject: [PATCH 039/146] Fix instantiatability checking We used to check only New nodes for instantiability. But sometimes these nodes have type constructors as types. The previous implementations of generics hid the problem, but in the new scheme the subtype test between New's type and its given self type fails if New's type lacks arguments. To compensate, we need to check the constructor call instead of the New itself. --- .../tools/dotc/transform/PostTyper.scala | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index c3a864bdfafa..049b96c561a0 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -94,7 +94,15 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran private var inJavaAnnot: Boolean = false - private var parentNews: Set[New] = Set() + private var noCheckNews: Set[New] = Set() + + def withNoCheckNews[T](ts: List[New])(op: => T): T = { + val saved = noCheckNews + noCheckNews ++= ts + try op finally noCheckNews = saved + } + + def isCheckable(t: New) = !inJavaAnnot && !noCheckNews.contains(t) private def transformAnnot(annot: Tree)(implicit ctx: Context): Tree = { val saved = inJavaAnnot @@ -185,6 +193,16 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran if (ctx.owner.enclosingMethod.isInlineMethod) ctx.error(SuperCallsNotAllowedInline(ctx.owner), tree.pos) super.transform(tree) + case tree: Apply => + methPart(tree) match { + case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => + // need to check instantiability here, because the type of the New itself + // might be a type constructor. + Checking.checkInstantiable(tree.tpe, nu.pos) + withNoCheckNews(nu :: Nil)(super.transform(tree)) + case _ => + super.transform(tree) + } case tree: TypeApply => val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) @@ -212,15 +230,12 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)) case tree: Template => - val saved = parentNews - parentNews ++= tree.parents.flatMap(newPart) - try { + withNoCheckNews(tree.parents.flatMap(newPart)) { val templ1 = paramFwd.forwardParamAccessors(tree) synthMth.addSyntheticMethods( superAcc.wrapTemplate(templ1)( super.transform(_).asInstanceOf[Template])) } - finally parentNews = saved case tree: DefDef => transformMemberDef(tree) superAcc.wrapDefDef(tree)(super.transform(tree).asInstanceOf[DefDef]) @@ -247,7 +262,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran case tree: MemberDef => transformMemberDef(tree) super.transform(tree) - case tree: New if !inJavaAnnot && !parentNews.contains(tree) => + case tree: New if isCheckable(tree) => Checking.checkInstantiable(tree.tpe, tree.pos) super.transform(tree) case tree @ Annotated(annotated, annot) => From a3d96f138a54e9ede07ea9195bf788eb408e11a2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 09:55:03 +0200 Subject: [PATCH 040/146] Adapt tpd.ClassDef and tpd.AnonClass to new scheme --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 5065b87f16ca..df15baf77b62 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -213,8 +213,16 @@ 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.parentRefs // @!!! adapt - val firstParent = cls.appliedRef.baseTypeWithArgs(firstParentRef.symbol) + val (firstParent, otherParents) = + if (config.Config.newScheme) { + val firstParent :: otherParents = cls.info.parentsNEW + (firstParent, otherParents) + } + else { + val firstParentRef :: otherParentRefs = cls.info.parentRefs // @!!! adapt + val firstParent = cls.appliedRef.baseTypeWithArgs(firstParentRef.symbol) + (firstParent, otherParentRefs) + } val superRef = if (cls is Trait) TypeTree(firstParent) else { @@ -229,7 +237,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info)) New(firstParent, constr.symbol.asTerm, superArgs) } - val parents = superRef :: otherParentRefs.map(TypeTree(_)) + val parents = superRef :: otherParents.map(TypeTree(_)) val selfType = if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls)) @@ -261,7 +269,9 @@ 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.parentRefs.head :: parents + if (parents.head.classSymbol.is(Trait)) + if (config.Config.newScheme) parents.head.parentsNEW.head :: parents + else parents.head.parentRefs.head :: parents else parents val cls = ctx.newNormalizedClassSymbol(owner, tpnme.ANON_FUN, Synthetic, parents1, coord = fns.map(_.pos).reduceLeft(_ union _)) From 0a27a7fe64da8dc408b530f8943ce61a4299788d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 09:57:37 +0200 Subject: [PATCH 041/146] Change capture conversion Use the full type as the prefix of a generated TypeArgRef instead of a skolem. Skolemization causes errors when skolems are used in type variable instantiations and then a different skolem is generated to check such instantiations. A test case is in pos/i2397.scala. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 63017b62d7dc..8b2d4aa28aef 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -976,7 +976,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def compareCaptured(arg1: Type, arg2: Type): Boolean = arg1 match { case arg1: TypeBounds => - val captured = TypeArgRef.fromParam(SkolemType(tp1), tparam.asInstanceOf[TypeSymbol]) + val captured = TypeArgRef.fromParam(tp1, tparam.asInstanceOf[TypeSymbol]) isSubArg(captured, arg2) case _ => false From 891022bbb3637645ee470f4a855d181673f07cc4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 10:00:33 +0200 Subject: [PATCH 042/146] Fix variances for wildcard arguments in TypeMaps and TypeAccumulators Parameter variance is only taken into account for concrete arguments, should be ignored for wildcards. Test case is ../pos/pos_valueclasses/t7818.scala. --- compiler/src/dotty/tools/dotc/core/Types.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 868e07755d3d..dc6ecce05642 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3989,8 +3989,10 @@ object Types { | NoPrefix => tp case tp: AppliedType => - def mapArg(arg: Type, tparam: ParamInfo): Type = - atVariance(variance * tparam.paramVariance)(this(arg)) + def mapArg(arg: Type, tparam: ParamInfo): Type = arg match { + case arg: TypeBounds => this(arg) + case _ => atVariance(variance * tparam.paramVariance)(this(arg)) + } derivedAppliedType(tp, this(tp.tycon), tp.args.zipWithConserve(tp.typeParams)(mapArg)) @@ -4420,7 +4422,10 @@ object Types { } else { val tparam = tparams.head - val acc = atVariance(variance * tparam.paramVariance)(this(x, args.head)) + val acc = args.head match { + case arg: TypeBounds => this(x, arg) + case arg => atVariance(variance * tparam.paramVariance)(this(x, arg)) + } foldArgs(acc, tparams.tail, args.tail) } foldArgs(this(x, tycon), tp.typeParams, args) From 52dd13148efcdaaba3b8294a66ab4c957d88ca84 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 10:01:01 +0200 Subject: [PATCH 043/146] Avoid cyclic reference in normalizeWildcardArgs --- compiler/src/dotty/tools/dotc/core/TypeApplications.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 682984b26756..94fc979801a7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -433,7 +433,8 @@ class TypeApplications(val self: Type) extends AnyVal { case dealiased @ TypeRef(prefix, _) => val (concreteArgs, concreteParams) = // @!!! optimize? args.zip(typParams).filter(!_._1.isInstanceOf[TypeBounds]).unzip - avoidParams(Set(tparam), v)( + if (tparam.isCompleting) TypeBounds.empty + else avoidParams(Set(tparam), v)( tparam.paramInfo.asSeenFrom(prefix, tparam.owner) .subst(concreteParams, concreteArgs)) case _ => From 51e67d1009510c20db44c2d4221d87fc723e4e12 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Aug 2017 17:47:41 +0200 Subject: [PATCH 044/146] Fix SuperAccessors I still understand the logic, but the new one matches more closely what scalac does. --- compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala index 7e59b770e02c..8cba190c0437 100644 --- a/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -297,7 +297,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val clazz = currentClass val host = hostForAccessorOf(sym, clazz) def accessibleThroughSubclassing = - validCurrentClass && (clazz.classInfo.selfType <:< sym.owner.appliedRef) && !clazz.is(Trait) + validCurrentClass && clazz.classInfo.selfType.derivesFrom(sym.owner) && !clazz.is(Trait) val isCandidate = ( sym.is(Protected) From 9f3b5a51b56cdb015c5408bdda30c200b8a2fb8a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 24 Aug 2017 17:40:22 +0200 Subject: [PATCH 045/146] Fix possible hole in constraint handling When called from `prune`, addLess might unify two type parameters which means that the constrained type parameter could no longer have a TypeBounds entry. So we need to handle that case. The problem was triggered in the doc unit tests --- .../src/dotty/tools/dotc/core/ConstraintHandling.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index b3bbc6b1570b..6a98dcf944d2 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -387,7 +387,12 @@ trait ConstraintHandling { else tp def addParamBound(bound: TypeParamRef) = - if (fromBelow) addLess(bound, param) else addLess(param, bound) + constraint.entry(param) match { + case _: TypeBounds => + if (fromBelow) addLess(bound, param) else addLess(param, bound) + case tp => + if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound) + } /** Drop all constrained parameters that occur at the toplevel in `bound` and * handle them by `addLess` calls. From 536c59704a2b662fab8ab12c9629d599ee564356 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 24 Aug 2017 17:41:27 +0200 Subject: [PATCH 046/146] Fix --- .../src/dotty/tools/dotc/config/Config.scala | 3 +- .../src/dotty/tools/dotc/core/Periods.scala | 9 +++ .../tools/dotc/core/SymDenotations.scala | 4 +- .../tools/dotc/core/TypeApplications.scala | 3 + .../src/dotty/tools/dotc/core/Types.scala | 78 ++++++++++++++++--- .../tools/dotc/core/tasty/TreeUnpickler.scala | 7 +- tests/neg/boundspropagation.scala | 5 +- 7 files changed, 89 insertions(+), 20 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index b578681f459e..b48bbce23e58 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -182,5 +182,6 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - val newScheme = false + val newScheme = true + val newBoundsScheme = true } diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index 892a1f59a5c4..3d4a288915d6 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -38,6 +38,15 @@ abstract class Periods extends DotClass { self: Context => } Period(runId, first, nxTrans) } + + /** Are all base types in the current period guaranteed to be the same as in period `p`? */ + def hasSameBaseTypesAs(p: Period) = { + val period = this.period + period == p || + period.runId == p.runId && + this.phases(period.phaseId).sameParentsStartId == + this.phases(p.phaseId).sameParentsStartId + } } object Periods { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c3a0d7d56a7e..c82077be6630 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1287,9 +1287,7 @@ object SymDenotations { } private def baseTypeCache(implicit ctx: Context): BaseTypeMap = { - if (myBaseTypeCachePeriod != ctx.period && - (myBaseTypeCachePeriod.runId != ctx.runId || - ctx.phases(myBaseTypeCachePeriod.phaseId).sameParentsStartId != ctx.phase.sameParentsStartId)) { + if (!ctx.hasSameBaseTypesAs(myBaseTypeCachePeriod)) { myBaseTypeCache = new BaseTypeMap myBaseTypeCachePeriod = ctx.period } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 94fc979801a7..5f25fdfc627a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -416,6 +416,8 @@ class TypeApplications(val self: Type) extends AnyVal { */ def normalizeWildcardArg(typParams: List[TypeSymbol])(arg: Type, tparam: TypeSymbol): Type = arg match { case TypeBounds(lo, hi) => + if (Config.newBoundsScheme) arg + else { def avoidParams(seen: Set[Symbol], v: Int): ApproximatingTypeMap = new ApproximatingTypeMap { variance = if (v >= 0) 1 else -1 def apply(t: Type) = t match { @@ -444,6 +446,7 @@ class TypeApplications(val self: Type) extends AnyVal { if (v > 0) hi & pbounds.hiBound else if (v < 0) lo | pbounds.loBound else arg recoverable_& pbounds + } case _ => arg } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index dc6ecce05642..a2a6618bb758 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -143,12 +143,6 @@ object Types { case _ => false } - /** Is this type exactly Nothing (no vars, aliases, refinements etc allowed)? */ - def isBottomType(implicit ctx: Context): Boolean = this match { - case tp: TypeRef => tp.symbol eq defn.NothingClass - case _ => false - } - /** Is this type a (neither aliased nor applied) reference to class `sym`? */ def isDirectRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match { case this1: TypeRef => @@ -225,6 +219,22 @@ object Types { else defn.NothingType } + /** Is this type exactly Nothing (no vars, aliases, refinements etc allowed)? */ + def isBottomType(implicit ctx: Context): Boolean = this match { + case tp: TypeRef => + val sym = tp.symbol + (sym eq defn.NothingClass) || (sym eq defn.Phantom_NothingClass) + case _ => false + } + + /** Is this type exactly Any (no vars, aliases, refinements etc allowed)? */ + def isTopType(implicit ctx: Context): Boolean = this match { + case tp: TypeRef => + val sym = tp.symbol + (sym eq defn.AnyClass) || (sym eq defn.Phantom_AnyClass) + case _ => false + } + /** Returns the type of the phantom lattice (i.e. the prefix of the phantom type) * - XYZ if XYZ extends scala.Phantom and this type is upper bounded XYZ.Any * - NoType otherwise @@ -1202,6 +1212,12 @@ object Types { def parentsNEW(implicit ctx: Context): List[Type] = this match { case tp @ AppliedType(tycon, args) if tycon.typeSymbol.isClass => tycon.parentsNEW.map(_.subst(tycon.typeSymbol.typeParams, args)) + case tp: TypeRef => + if (tp.info.isInstanceOf[TempClassInfo]) { + tp.reloadDenot() + assert(!tp.info.isInstanceOf[TempClassInfo]) + } + tp.info.parentsNEW case tp: TypeProxy => tp.superType.parentsNEW case _ => Nil @@ -1760,6 +1776,8 @@ object Types { } } + def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) + protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) else if (!allowPrivate) prefix.nonPrivateMember(name) @@ -1853,7 +1871,7 @@ object Types { case AndType(base1, base2) => argForParam(base1) & argForParam(base2) case _ => if (pre.termSymbol is Package) argForParam(pre.select(nme.PACKAGE)) - else if (pre.isBottomType) pre.bottomType + else if (pre.isBottomType) pre else NoType } } @@ -3271,8 +3289,36 @@ object Types { assert(prefix.isInstanceOf[ValueType]) assert(idx >= 0) + private[this] var underlyingCache: Type = _ + private[this] var underlyingCachePeriod = Nowhere + + def computeUnderlying(implicit ctx: Context): Type = { + val cls = clsRef.symbol + val args = prefix.baseType(cls).argInfos + val typeParams = cls.typeParams + + val concretized = TypeArgRef.concretizeArgs(args, prefix, clsRef) + def rebase(arg: Type) = arg.subst(typeParams, concretized) + + val arg = args(idx) + val tparam = typeParams(idx) + val v = tparam.paramVariance + val pbounds = tparam.paramInfo + if (v > 0 && pbounds.loBound.dealias.isBottomType) arg.hiBound & rebase(pbounds.hiBound) + else if (v < 0 && pbounds.hiBound.dealias.isTopType) arg.loBound | rebase(pbounds.loBound) + else arg recoverable_& rebase(pbounds) + } + override def underlying(implicit ctx: Context): Type = - prefix.baseType(clsRef.symbol).argInfos.apply(idx) + if (Config.newBoundsScheme) { + if (!ctx.hasSameBaseTypesAs(underlyingCachePeriod)) { + underlyingCache = computeUnderlying + underlyingCachePeriod = ctx.period + } + underlyingCache + } + else prefix.baseType(clsRef.symbol).argInfos.apply(idx) + def derivedTypeArgRef(prefix: Type)(implicit ctx: Context): Type = if (prefix eq this.prefix) this else TypeArgRef(prefix, clsRef, idx) override def computeHash = doHash(idx, prefix, clsRef) @@ -3287,6 +3333,14 @@ object Types { val cls = tparam.owner apply(prefix, cls.typeRef, cls.typeParams.indexOf(tparam)) } + + def concretizeArgs(args: List[Type], prefix: Type, clsRef: TypeRef)(implicit ctx: Context): List[Type] = { + def concretize(arg: Type, j: Int) = arg match { + case arg: TypeBounds => TypeArgRef(prefix, clsRef, j) + case arg => arg + } + args.zipWithConserve(args.indices.toList)(concretize) + } } // ----- BoundTypes: ParamRef, RecThis ---------------------------------------- @@ -3603,7 +3657,7 @@ object Types { override def computeHash = doHash(cls, prefix) - override def toString = s"ClassInfo($prefix, $cls)" + override def toString = s"ClassInfo($prefix, $cls, $classParentsNEW)" } class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: DotClass) @@ -3626,6 +3680,12 @@ object Types { denot.info = derivedClassInfo(classParentsNEW = parents) suspensions.foreach(_(ctx)) } + + override def derivedClassInfo(prefix: Type)(implicit ctx: Context) = + if (prefix eq this.prefix) this + else new TempClassInfo(prefix, cls, decls, selfInfo) + + override def toString = s"TempClassInfo($prefix, $cls)" } object ClassInfo { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 12657342321c..cee72f0f33fb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -715,13 +715,11 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi private def readTemplate(implicit ctx: Context): Template = { val start = currentAddr val cls = ctx.owner.asClass - def setClsInfo(parents: List[Type], selfType: Type) = - cls.info = ClassInfo(cls.owner.thisType, cls, parents, cls.unforcedDecls, selfType) val assumedSelfType = if (cls.is(Module) && cls.owner.isClass) TermRef.withSig(cls.owner.thisType, cls.name.sourceModuleName, Signature.NotAMethod) else NoType - setClsInfo(Nil, assumedSelfType) + cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() assert(readByte() == TEMPLATE) val end = readEnd() @@ -740,7 +738,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType) } else EmptyValDef - setClsInfo(parentRefs, if (self.isEmpty) NoType else self.tpt.tpe) + cls.info = ClassInfo(cls.owner.thisType, cls, parentRefs, cls.unforcedDecls, + if (self.isEmpty) NoType else self.tpt.tpe) cls.setNoInitsFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] diff --git a/tests/neg/boundspropagation.scala b/tests/neg/boundspropagation.scala index dd4ebf5139e8..0fc36e8a3d9e 100644 --- a/tests/neg/boundspropagation.scala +++ b/tests/neg/boundspropagation.scala @@ -25,8 +25,7 @@ object test3 { } } -// Example contributed by Jason. I believe this should not typecheck, -// even though scalac does typecheck it. +// Example contributed by Jason. object test4 { class Base { type N @@ -34,7 +33,7 @@ object test4 { class Tree[-S, -T >: Option[S]] def g(x: Any): Tree[_, _ <: Option[N]] = x match { - case y: Tree[_, _] => y // error + case y: Tree[_, _] => y // works now (because of capture conversion?) } } } From c4def34b98b13d20d7270827db8a6cb29fa30b6e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 24 Aug 2017 17:47:13 +0200 Subject: [PATCH 047/146] Fix printing of TypeBounds Only use "=" if it is a TypeAlias. This fixes an observed TestPickling difference. --- .../tools/dotc/printing/PlainPrinter.scala | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index dfb8838658b4..623cbdc07c28 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -317,17 +317,15 @@ class PlainPrinter(_ctx: Context) extends Printer { /** String representation of a definition's type following its name */ protected def toTextRHS(tp: Type): Text = controlled { homogenize(tp) match { + case tp: TypeAlias => + val eql = + if (tp.variance == 1) " =+ " + else if (tp.variance == -1) " =- " + else " = " + eql ~ toText(tp.alias) case tp @ TypeBounds(lo, hi) => - if (lo eq hi) { - val eql = - if (tp.variance == 1) " =+ " - else if (tp.variance == -1) " =- " - else " = " - eql ~ toText(lo) - } - else - (if (lo isRef defn.NothingClass) Text() else " >: " ~ toText(lo)) ~ - (if (hi isRef defn.AnyClass) Text() else " <: " ~ toText(hi)) + (if (lo isRef defn.NothingClass) Text() else " >: " ~ toText(lo)) ~ + (if (hi isRef defn.AnyClass) Text() else " <: " ~ toText(hi)) case tp @ ClassInfo(pre, cls, cparents, decls, selfInfo) => val preText = toTextLocal(pre) val (tparams, otherDecls) = decls.toList partition treatAsTypeParam From 6a027179334b2f251d3837f2f50cb45341099d8f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 24 Aug 2017 17:53:06 +0200 Subject: [PATCH 048/146] Refine Space#refine to handle AppliedTypes Unfortunately, this does not fix pattern matching exhaustivity checks for the new scheme. Exhaustivity makes use of the following scheme. Say we want to decompose Option[Int] to Some. The new scheme gives us Some[Int]. But exhaustivity, working on refined types will give us Some { type Option$$T = Int } instead. This type is weird, because the `Some` class already contains an override type Option$$T = Some$$T So we end up with two conflicting bindings. Using natuve aplications, there's no way we can get this (I would argue malformed) type. Unfortunately, current exhaustivity checking seems to rely having a type like this. --- .../tools/dotc/transform/patmat/Space.scala | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 1451fedc2d8f..63db4da5a59b 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -558,7 +558,16 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { * definition! */ def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match { - case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2)) + case (tp1: RefinedType, _: TypeRef) => + val res = tp1.wrapIfMember(refine(tp1.parent, tp2)) + debug.println(i"refine($tp1, $tp2) = $res") + res + case (tp1 @ AppliedType(tycon, args), tp2: TypeRef) + if config.Config.newScheme && tp2.symbol.typeParams.nonEmpty && tp2.symbol.derivesFrom(tycon.typeSymbol) => + val tp1a = tp1.derivedAppliedType(refine(tycon, tp2), args) + val res = derivingType(tp1a.asInstanceOf[AppliedType], tp2) + debug.println(i"refine($tp1, $tp2) = $res") + res case (tp1: AppliedType, _) => refine(tp1.superType, tp2) case (tp1: HKApply, _) => refine(tp1.superType, tp2) case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) => @@ -568,6 +577,42 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { case _ => tp2 } + def derivingType(tp1: AppliedType, clsRef: TypeRef): Type = { + val cls = clsRef.symbol + val typeParams = cls.typeParams + if (tp1.tycon.typeSymbol == cls) tp1 + else { + val abstracted = PolyType.fromParams( + cls.typeParams, clsRef.appliedTo(typeParams.map(_.typeRef))).asInstanceOf[PolyType] + val (schema, _) = constrained(abstracted, untpd.EmptyTree) + schema <:< tp1 + val constraint = ctx.typerState.constraint + def avoidParamRefs(seen: Set[TypeParamRef], v: Int): ApproximatingTypeMap = new ApproximatingTypeMap { + variance = if (v >= 0) 1 else -1 + def apply(t: Type) = t match { + case t: TypeParamRef if schema.paramRefs contains t => + val lo = atVariance(-variance)(apply(constraint.fullLowerBound(t))) + val hi = + if (seen.contains(t)) t.topType + else avoidParamRefs(seen + t, variance)(constraint.fullUpperBound(t)) + range(lo, hi) + case _ => mapOver(t) + } + } + val boundss = abstracted.paramRefs.map(constraint.fullBounds) + def boundsToArg(bounds: TypeBounds, tparam: TypeSymbol): Type = { + val v = tparam.paramVariance + val arg = + if (v < 0 || (bounds.hi frozen_<:< bounds.lo)) bounds.lo + else if (v > 0) bounds.hi + else bounds + avoidParamRefs(Set.empty, v)(arg) + } + val args = (boundss, typeParams).zipped.map(boundsToArg) + clsRef.appliedTo(args) + } + } + /** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */ def canDecompose(tp: Type): Boolean = { val dealiasedTp = tp.dealias From 2da0049be382f37bcc2f0a0d9188d7780877e150 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 25 Aug 2017 08:44:18 +0200 Subject: [PATCH 049/146] Fix implicit selection for views - First, always report type mismatch if implicit search is disabled. Previously, we did not do this if expected type is prototype, which led to spurious ambiguity errors. - Second, fix logic for avoiding $conforms as an implicit conversion. It slipped through in the -language:Scala2 case because it is an instance of a unary function. --- .../dotty/tools/dotc/typer/Implicits.scala | 7 +++-- .../src/dotty/tools/dotc/typer/Typer.scala | 28 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6f75dd9df1b7..18fc6c0a53c1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -100,10 +100,11 @@ object Implicits { // nothing since it only relates subtype with supertype. // // We keep the old behavior under -language:Scala2. - val isFunctionInS2 = ctx.scala2Mode && tpw.derivesFrom(defn.FunctionClass(1)) + val isFunctionInS2 = + ctx.scala2Mode && tpw.derivesFrom(defn.FunctionClass(1)) && ref.symbol != defn.Predef_conforms val isImplicitConverter = tpw.derivesFrom(defn.Predef_ImplicitConverter) - val isConforms = - tpw.derivesFrom(defn.Predef_Conforms) && ref.symbol != defn.Predef_conforms + val isConforms = // An implementation of <:< counts as a view, except that $conforms is always omitted + tpw.derivesFrom(defn.Predef_Conforms) && ref.symbol != defn.Predef_conforms !(isFunctionInS2 || isImplicitConverter || isConforms) } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index bd14f4a580ac..c429771a5c00 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2205,16 +2205,24 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => } // try an implicit conversion - inferView(tree, pt) match { - case SearchSuccess(inferred, _, _, _) => - adapt(inferred, pt)(ctx.retractMode(Mode.ImplicitsEnabled)) - case failure: SearchFailure => - val prevConstraint = ctx.typerState.constraint - if (pt.isInstanceOf[ProtoType] && !failure.isInstanceOf[AmbiguousImplicits]) tree - else if (isFullyDefined(wtp, force = ForceDegree.all) && - ctx.typerState.constraint.ne(prevConstraint)) adapt(tree, pt) - else err.typeMismatch(tree, pt, failure) - } + val prevConstraint = ctx.typerState.constraint + def recover(failure: SearchFailure) = + if (isFullyDefined(wtp, force = ForceDegree.all) && + ctx.typerState.constraint.ne(prevConstraint)) adapt(tree, pt) + else err.typeMismatch(tree, pt, failure) + if (ctx.mode.is(Mode.ImplicitsEnabled)) + inferView(tree, pt) match { + case SearchSuccess(inferred, _, _, _) => + adapt(inferred, pt)(ctx.retractMode(Mode.ImplicitsEnabled)) + case failure: SearchFailure => + if (pt.isInstanceOf[ProtoType] && !failure.isInstanceOf[AmbiguousImplicits]) + // don't report the failure but return the tree unchanged. This + // wil cause a failure at the next level out, which usually gives + // a better error message. + tree + else recover(failure) + } + else recover(NoImplicitMatches) } def adaptType(tp: Type): Tree = { From 9063347ed037403d642c60bf2eb907485edbe437 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 26 Aug 2017 09:51:27 +0200 Subject: [PATCH 050/146] Fix sigName for AppliedType --- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 8969fa8b44e1..b231ca1b0d66 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -532,7 +532,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else normalizeClass(sym.asClass).fullName.asTypeName case tp: AppliedType => - sigName(if (tp.tycon.isRef(defn.ArrayClass)) this(tp) else tp.superType) + sigName(if (tp.tycon.isRef(defn.ArrayClass)) this(tp) else tp.underlying) case ErasedValueType(_, underlying) => sigName(underlying) case defn.ArrayOf(elem) => // @!!! From b0a2aa2823fbe6ca5a814d104798c2ec4717aa88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 13:33:11 +0200 Subject: [PATCH 051/146] Handle Java raw types in isSubType We were missing the case where a supertype is an unapplied Java type constructor. Such a type is not a higher-kinded type, but a raw type. --- compiler/src/dotty/tools/dotc/core/TypeComparer.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 8b2d4aa28aef..c167a9cfd377 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -371,7 +371,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val cls2 = tp2.symbol if (cls2.isClass) { val base = tp1.baseType(cls2) - if (base.exists && (base ne tp1)) return isSubType(base, tp2) + if (base.exists) { + if (cls2.is(JavaDefined)) return base.typeSymbol == cls2 + if (base ne tp1) return isSubType(base, tp2) + } if (cls2 == defn.SingletonClass && tp1.isStable) return true } fourthTry(tp1, tp2) From 36b1550fd5a33aaea424dc810710f23f55450281 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 13:34:54 +0200 Subject: [PATCH 052/146] Don't check variances when comparing type lambdas in Scala2 mode There were some failures when compiling stdlib. It's explained in the code comment. --- .../dotty/tools/dotc/core/TypeComparer.scala | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index c167a9cfd377..092cf4ef4132 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -446,7 +446,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2: HKTypeLambda => def compareTypeLambda: Boolean = tp1.stripTypeVar match { case tp1: HKTypeLambda => - /* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail + /* Don't compare bounds or variances of lambdas under language:Scala2. + * (1) If we compare bounds, t2994 will fail. * The issue is that, logically, bounds should compare contravariantly, * but that would invalidate a pattern exploited in t2994: * @@ -458,17 +459,32 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * * Note: it would be nice if this could trigger a migration warning, but I * am not sure how, since the code is buried so deep in subtyping logic. + * + * (2) If we compare variances, compilation of scala.collection.mutable.Set wil fail. + * The issue is the following: + * + * Error overriding method companion in trait Iterable of type + * => scala.collection.generic.GenericCompanion[[+A] => scala.collection.Iterable[A]]; + * method companion of type + * => scala.collection.generic.GenericCompanion[[A] => scala.collection.mutable.Set[A]] + * has incompatible type. + * + * Indeed, a non-variant Set is not a legal substitute for a covariant Iterable. + * Every instantiated Set is an Iterable, but the type constructor Iterable can be + * passed to a covariant type constructor CC[+X] whereas a non-variant Set cannot. */ def boundsOK = ctx.scala2Mode || tp1.typeParams.corresponds(tp2.typeParams)((tparam1, tparam2) => isSubType(tparam2.paramInfo.subst(tp2, tp1), tparam1.paramInfo)) + def variancesOK = + ctx.scala2Mode || + variancesConform(tp1.typeParams, tp2.typeParams) val saved = comparedTypeLambdas comparedTypeLambdas += tp1 comparedTypeLambdas += tp2 try - variancesConform(tp1.typeParams, tp2.typeParams) && - boundsOK && + variancesOK && boundsOK && isSubType(tp1.resType, tp2.resType.subst(tp2, tp1)) finally comparedTypeLambdas = saved case _ => From dcd8fd309665a50f77d5fe85d9bbf142879f66dc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 13:36:33 +0200 Subject: [PATCH 053/146] Don't try to simplify & / | types written as types We should leave an explicit & or | type as an AndType or OrType. Failure to do this led to cyclic references when compiling stdlib. Question to resolve: Should we disable all sorts of simplifications when compiling a type tree? --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index bf80e7cab401..4519eac55bda 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -105,9 +105,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object. 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) => + case AndType(l, r) if !ctx.mode.is(Mode.Type) => simplify(l, theMap) & simplify(r, theMap) - case OrType(l, r) => + case OrType(l, r) if !ctx.mode.is(Mode.Type) => simplify(l, theMap) | simplify(r, theMap) case _ => (if (theMap != null) theMap else new SimplifyMap).mapOver(tp) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 291b23668bb1..6c435ad222e5 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -468,10 +468,10 @@ trait TypeAssigner { tree.withType(ref.tpe) def assignType(tree: untpd.AndTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = - tree.withType(inSameUniverse(_ & _, left.tpe, right, "an `&`")) + tree.withType(inSameUniverse(AndType(_, _), left.tpe, right, "an `&`")) def assignType(tree: untpd.OrTypeTree, left: Tree, right: Tree)(implicit ctx: Context) = - tree.withType(inSameUniverse(_ | _, left.tpe, right, "an `|`")) + tree.withType(inSameUniverse(OrType(_, _), left.tpe, right, "an `|`")) /** Assign type of RefinedType. * Refinements are typed as if they were members of refinement class `refineCls`. From 59ce28ffa2ba0c4be358d1c33584b85dd2077e8d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 13:30:09 +0200 Subject: [PATCH 054/146] Hash-cons applied types in their own table --- .../src/dotty/tools/dotc/core/Contexts.scala | 6 +++- .../src/dotty/tools/dotc/core/Types.scala | 28 +++++------------ .../src/dotty/tools/dotc/core/Uniques.scala | 31 +++++++++++++++++++ 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index d5fccd928643..bb061eaea749 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -613,15 +613,19 @@ object Contexts { /** A table for hash consing unique refined types */ private[dotc] val uniqueRefinedTypes = new RefinedUniques // @!!! replace with uniqueAppliedTypes + /** A table for hash consing unique refined types */ + private[dotc] val uniqueAppliedTypes = new AppliedUniques + /** A table for hash consing unique named types */ private[core] val uniqueNamedTypes = new NamedTypeUniques /** A table for hash consing unique type bounds */ - private[core] val uniqueTypeAliases = new TypeAliasUniques + private[core] val uniqueTypeAliases = new TypeAliasUniques // @!!! replace private def uniqueSets = Map( "uniques" -> uniques, "uniqueRefinedTypes" -> uniqueRefinedTypes, + "uniqueAppliedTypes" -> uniqueAppliedTypes, "uniqueNamedTypes" -> uniqueNamedTypes, "uniqueTypeAliases" -> uniqueTypeAliases) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a2a6618bb758..6ed2cbeb44a1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3177,30 +3177,18 @@ object Types { 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) + final class CachedAppliedType(tycon: Type, args: List[Type], hc: Int) extends AppliedType(tycon, args) { + myHash = hc + override def computeHash = unsupported("computeHash") + } object AppliedType { - def apply(tycon: Type, args: List[Type])(implicit ctx: Context) = - unique(new CachedAppliedType(tycon, args)).checkInst + def apply(tycon: Type, args: List[Type])(implicit ctx: Context) = { + assertUnerased() + ctx.base.uniqueAppliedTypes.enterIfNew(tycon, args) + } } object ClassRef { diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index cb9670c69956..a8c325995ab5 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -91,6 +91,37 @@ object Uniques { } } + + final class AppliedUniques extends HashSet[AppliedType](Config.initialUniquesCapacity) with Hashable { + override def hash(x: AppliedType): Int = x.hash + + private def findPrevious(h: Int, tycon: Type, args: List[Type]): AppliedType = { + var e = findEntryByHash(h) + while (e != null) { + def sameArgs(args1: List[Type], args2: List[Type]): Boolean = { + val empty1 = args1.isEmpty + val empty2 = args2.isEmpty + if (empty1) empty2 + else (!empty2 && (args1.head eq args2.head) && sameArgs(args1.tail, args2.tail)) + } + if ((e.tycon eq tycon) && sameArgs(e.args, args)) return e + e = nextEntryByHash(h) + } + e + } + + def enterIfNew(tycon: Type, args: List[Type]): AppliedType = { + val h = doHash(tycon, args) + def newType = new CachedAppliedType(tycon, args, h) + if (monitored) recordCaching(h, classOf[CachedAppliedType]) + if (h == NotCached) newType + else { + val r = findPrevious(h, tycon, args) + if (r ne null) r else addEntryAfterScan(newType) + } + } + } + final class RefinedUniques extends HashSet[RefinedType](Config.initialUniquesCapacity) with Hashable { override val hashSeed = classOf[CachedRefinedType].hashCode // some types start life as CachedRefinedTypes, need to have same hash seed override def hash(x: RefinedType): Int = x.hash From 60d7b85f0d245379ded1f937d365f201227c3f43 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 16:22:07 +0200 Subject: [PATCH 055/146] Make ParamRefs unique types. They were case classes before, but not uniquely hashed. This meant that the hash cons sepcialization for AppliedTypes failed to work in many cases. since ParamRef arguments were not `eq` to each other. Consequently, we got timeouts for compiling stdlib. --- .../tools/dotc/core/OrderingConstraint.scala | 4 +- .../src/dotty/tools/dotc/core/Types.scala | 44 ++++++++++++++----- .../dotty/tools/dotc/typer/Applications.scala | 2 +- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index b83061e8bc35..dec9e8305730 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -463,12 +463,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds, (poly, entries) <- boundsMap.toList n <- 0 until paramCount(entries) if entries(n).exists - } yield TypeParamRef(poly, n) + } yield TypeParamRef.uncached(poly, n) def forallParams(p: TypeParamRef => Boolean): Boolean = { boundsMap.foreachBinding { (poly, entries) => for (i <- 0 until paramCount(entries)) - if (isBounds(entries(i)) && !p(TypeParamRef(poly, i))) return false + if (isBounds(entries(i)) && !p(TypeParamRef.uncached(poly, i))) return false } true } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6ed2cbeb44a1..c668f226ae75 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2634,7 +2634,7 @@ object Types { def paramNames: List[ThisName] def paramInfos: List[PInfo] def resType: Type - def newParamRef(n: Int): ParamRefType + def newParamRef(n: Int)(implicit ctx: Context): ParamRefType override def resultType(implicit ctx: Context) = resType @@ -2648,7 +2648,12 @@ object Types { final def isTypeLambda = isInstanceOf[TypeLambda] final def isHigherKinded = isInstanceOf[TypeProxy] - lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef) + private var myParamRefs: List[ParamRefType] = null + + def paramRefs(implicit ctx: Context): List[ParamRefType] = { + if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef) + myParamRefs + } protected def computeSignature(implicit ctx: Context) = resultSignature @@ -2809,7 +2814,7 @@ object Types { */ def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps - def newParamRef(n: Int) = TermParamRef(this, n) + def newParamRef(n: Int)(implicit ctx: Context) = TermParamRef(this, n) } abstract case class MethodType(paramNames: List[TermName])( @@ -2964,7 +2969,7 @@ object Types { def isDependent(implicit ctx: Context): Boolean = true def isParamDependent(implicit ctx: Context): Boolean = true - def newParamRef(n: Int) = TypeParamRef(this, n) + def newParamRef(n: Int)(implicit ctx: Context) = TypeParamRef(this, n) lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) @@ -3122,7 +3127,7 @@ object Types { def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance - def toArg: Type = TypeParamRef(tl, n) + def toArg(implicit ctx: Context): Type = TypeParamRef(tl, n) def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n) } @@ -3336,7 +3341,7 @@ object Types { abstract class BoundType extends CachedProxyType with ValueType { type BT <: Type val binder: BT - def copyBoundType(bt: BT): Type + def copyBoundType(bt: BT)(implicit ctx: Context): Type } abstract class ParamRef extends BoundType { @@ -3365,14 +3370,21 @@ object Types { } } - case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { + abstract case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { type BT = TermLambda - def copyBoundType(bt: BT) = TermParamRef(bt, paramNum) + def copyBoundType(bt: BT)(implicit ctx: Context) = TermParamRef(bt, paramNum) + } + + class CachedTermParamRef(binder: TermLambda, paramNum: Int) extends TermParamRef(binder, paramNum) + + object TermParamRef { + def apply(binder: TermLambda, paramNum: Int)(implicit ctx: Context) = + unique(new CachedTermParamRef(binder, paramNum)) } - case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { + abstract case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { type BT = TypeLambda - def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum) + def copyBoundType(bt: BT)(implicit ctx: Context) = TypeParamRef(bt, paramNum) /** Looking only at the structure of `bound`, is one of the following true? * - fromBelow and param <:< bound @@ -3388,11 +3400,21 @@ object Types { } } + class ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int) extends TypeParamRef(binder, paramNum) + + object TypeParamRef { + def apply(binder: TypeLambda, paramNum: Int)(implicit ctx: Context) = + unique(new ConcreteTypeParamRef(binder, paramNum)) + + def uncached(binder: TypeLambda, paramNum: Int) = + new ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int) + } + /** a self-reference to an enclosing recursive type. */ case class RecThis(binder: RecType) extends BoundType with SingletonType { type BT = RecType override def underlying(implicit ctx: Context) = binder - def copyBoundType(bt: BT) = RecThis(bt) + def copyBoundType(bt: BT)(implicit ctx: Context) = RecThis(bt) // need to customize hashCode and equals to prevent infinite recursion // between RecTypes and RecRefs. diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 218ec3f704a3..8569a609dae1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -409,7 +409,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def addTyped(arg: Arg, formal: Type): Type => Type = { addArg(typedArg(arg, formal), formal) if (methodType.isParamDependent) - safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg)) + safeSubstParam(_, methodType.paramRefs.apply(n), typeOfArg(arg)) else identity } From bec92d18cf531467c9b98c2d39f07f4852d41f95 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 27 Aug 2017 13:38:10 +0200 Subject: [PATCH 056/146] Refine statistics - new option -Ydetailed-stats provdies stats without starting a "heart-beat" thread. - track times of all phase groups under -Ydetailed-stats, even if -verbose if off. - better tracking of base types, which seem to be more prominent and expensive under new scheme. --- compiler/src/dotty/tools/dotc/Run.scala | 25 ++++++++++--------- .../tools/dotc/config/ScalaSettings.scala | 3 ++- .../tools/dotc/core/SymDenotations.scala | 11 ++++++-- .../src/dotty/tools/dotc/util/Stats.scala | 18 ++++++++++--- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 10ccc59a3e5f..e0044268a6d9 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -118,20 +118,21 @@ class Run(comp: Compiler, ictx: Context) { ctx.usePhases(phases) var lastPrintedTree: PrintedTree = NoPrintedTree for (phase <- ctx.allPhases) - if (phase.isRunnable) { - val start = System.currentTimeMillis - units = phase.runOn(units) - if (ctx.settings.Xprint.value.containsPhase(phase)) { - for (unit <- units) { - lastPrintedTree = - printTree(lastPrintedTree)(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) + if (phase.isRunnable) + Stats.trackTime(s"$phase ms ") { + val start = System.currentTimeMillis + units = phase.runOn(units) + if (ctx.settings.Xprint.value.containsPhase(phase)) { + for (unit <- units) { + lastPrintedTree = + printTree(lastPrintedTree)(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) + } } + ctx.informTime(s"$phase ", start) + Stats.record(s"total trees at end of $phase", ast.Trees.ntrees) + for (unit <- units) + Stats.record(s"retained typed trees at end of $phase", unit.tpdTree.treeSize) } - ctx.informTime(s"$phase ", start) - Stats.record(s"total trees at end of $phase", ast.Trees.ntrees) - for (unit <- units) - Stats.record(s"retained typed trees at end of $phase", unit.tpdTree.treeSize) - } if (!ctx.reporter.hasErrors) Rewrites.writeBack() } diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index b0a1321a395c..57cb5bc84885 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -87,7 +87,8 @@ class ScalaSettings extends Settings.SettingGroup { val YmethodInfer = BooleanSetting("-Yinfer-argument-types", "Infer types for arguments of overriden methods.") val YtraceContextCreation = BooleanSetting("-Ytrace-context-creation", "Store stack trace of context creations.") val YshowSuppressedErrors = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally supressed.") - val Yheartbeat = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations.") + val YdetailedStats = BooleanSetting("-Ydetailed-stats", "show detailed internal compiler stats (needs Stats.enabled to be set to true).") + val Yheartbeat = BooleanSetting("-Ydetailed-stats", "show heartbeat stack trace of compiler operations (needs Stats.enabled to be set to true).") val Yprintpos = BooleanSetting("-Yprintpos", "show tree positions.") val YnoDeepSubtypes = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.") val YnoPatmatOpt = BooleanSetting("-Yno-patmat-opt", "disable all pattern matching optimizations.") diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index c82077be6630..ea22321b08c1 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1638,7 +1638,10 @@ object SymDenotations { } def computeBaseTypeOf(tp: Type): Type = { - Stats.record("computeBaseTypeOf") + if (Stats.monitored) { + Stats.record("computeBaseType, total") + Stats.record(s"computeBaseType, ${tp.getClass}") + } if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty) symbol.appliedRef else tp match { @@ -1675,7 +1678,11 @@ object SymDenotations { if (basetp == null) { btrCache.put(tp, NoPrefix) basetp = computeBaseTypeOf(tp) - if (isCachable(tp, baseTypeCache)) btrCache.put(tp, basetp) + if (!basetp.exists) Stats.record("base type miss") + if (isCachable(tp, baseTypeCache)) { + if (!basetp.exists) Stats.record("cached base type miss") + btrCache.put(tp, basetp) + } else btrCache.remove(tp) } else if (basetp == NoPrefix) throw CyclicReference(this) diff --git a/compiler/src/dotty/tools/dotc/util/Stats.scala b/compiler/src/dotty/tools/dotc/util/Stats.scala index b7e0996f5fc1..970b44248d70 100644 --- a/compiler/src/dotty/tools/dotc/util/Stats.scala +++ b/compiler/src/dotty/tools/dotc/util/Stats.scala @@ -42,6 +42,16 @@ import collection.mutable finally stack = stack.tail } else op + @inline + def trackTime[T](fn: String)(op: => T) = + if (enabled) doTrackTime(fn)(op) else op + + def doTrackTime[T](fn: String)(op: => T) = + if (monitored) { + val start = System.nanoTime + try op finally record(fn, ((System.nanoTime - start) / 1000).toInt) + } else op + class HeartBeat extends Thread() { @volatile private[Stats] var continue = true @@ -61,10 +71,10 @@ import collection.mutable } } - def monitorHeartBeat[T](op: => T)(implicit ctx: Context) = { - if (ctx.settings.Yheartbeat.value) { - var hb = new HeartBeat() - hb.start() + def maybeMonitored[T](op: => T)(implicit ctx: Context) = { + if (ctx.settings.YdetailedStats.value) { + val hb = new HeartBeat() + if (ctx.settings.Yheartbeat.value) hb.start() monitored = true try op finally { From f92b5fc67c2a2d7216598679b4fe0bc47937dad3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 28 Aug 2017 08:20:27 +0200 Subject: [PATCH 057/146] Make ParamRefs unique types. They were case classes before, but not uniquely hashed. This meant that the hash cons sepcialization for AppliedTypes failed to work in many cases. since ParamRef arguments were not `eq` to each other. Consequently, we got timeouts for compiling stdlib. (reverted from commit edd518f16b8071c1d876cceb77c3a3b98da3af48) --- .../tools/dotc/core/OrderingConstraint.scala | 4 +- .../src/dotty/tools/dotc/core/Types.scala | 44 +++++-------------- .../dotty/tools/dotc/typer/Applications.scala | 2 +- 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index dec9e8305730..b83061e8bc35 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -463,12 +463,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds, (poly, entries) <- boundsMap.toList n <- 0 until paramCount(entries) if entries(n).exists - } yield TypeParamRef.uncached(poly, n) + } yield TypeParamRef(poly, n) def forallParams(p: TypeParamRef => Boolean): Boolean = { boundsMap.foreachBinding { (poly, entries) => for (i <- 0 until paramCount(entries)) - if (isBounds(entries(i)) && !p(TypeParamRef.uncached(poly, i))) return false + if (isBounds(entries(i)) && !p(TypeParamRef(poly, i))) return false } true } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c668f226ae75..6ed2cbeb44a1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2634,7 +2634,7 @@ object Types { def paramNames: List[ThisName] def paramInfos: List[PInfo] def resType: Type - def newParamRef(n: Int)(implicit ctx: Context): ParamRefType + def newParamRef(n: Int): ParamRefType override def resultType(implicit ctx: Context) = resType @@ -2648,12 +2648,7 @@ object Types { final def isTypeLambda = isInstanceOf[TypeLambda] final def isHigherKinded = isInstanceOf[TypeProxy] - private var myParamRefs: List[ParamRefType] = null - - def paramRefs(implicit ctx: Context): List[ParamRefType] = { - if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef) - myParamRefs - } + lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef) protected def computeSignature(implicit ctx: Context) = resultSignature @@ -2814,7 +2809,7 @@ object Types { */ def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps - def newParamRef(n: Int)(implicit ctx: Context) = TermParamRef(this, n) + def newParamRef(n: Int) = TermParamRef(this, n) } abstract case class MethodType(paramNames: List[TermName])( @@ -2969,7 +2964,7 @@ object Types { def isDependent(implicit ctx: Context): Boolean = true def isParamDependent(implicit ctx: Context): Boolean = true - def newParamRef(n: Int)(implicit ctx: Context) = TypeParamRef(this, n) + def newParamRef(n: Int) = TypeParamRef(this, n) lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) @@ -3127,7 +3122,7 @@ object Types { def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance - def toArg(implicit ctx: Context): Type = TypeParamRef(tl, n) + def toArg: Type = TypeParamRef(tl, n) def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n) } @@ -3341,7 +3336,7 @@ object Types { abstract class BoundType extends CachedProxyType with ValueType { type BT <: Type val binder: BT - def copyBoundType(bt: BT)(implicit ctx: Context): Type + def copyBoundType(bt: BT): Type } abstract class ParamRef extends BoundType { @@ -3370,21 +3365,14 @@ object Types { } } - abstract case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { + case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { type BT = TermLambda - def copyBoundType(bt: BT)(implicit ctx: Context) = TermParamRef(bt, paramNum) - } - - class CachedTermParamRef(binder: TermLambda, paramNum: Int) extends TermParamRef(binder, paramNum) - - object TermParamRef { - def apply(binder: TermLambda, paramNum: Int)(implicit ctx: Context) = - unique(new CachedTermParamRef(binder, paramNum)) + def copyBoundType(bt: BT) = TermParamRef(bt, paramNum) } - abstract case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { + case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { type BT = TypeLambda - def copyBoundType(bt: BT)(implicit ctx: Context) = TypeParamRef(bt, paramNum) + def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum) /** Looking only at the structure of `bound`, is one of the following true? * - fromBelow and param <:< bound @@ -3400,21 +3388,11 @@ object Types { } } - class ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int) extends TypeParamRef(binder, paramNum) - - object TypeParamRef { - def apply(binder: TypeLambda, paramNum: Int)(implicit ctx: Context) = - unique(new ConcreteTypeParamRef(binder, paramNum)) - - def uncached(binder: TypeLambda, paramNum: Int) = - new ConcreteTypeParamRef(binder: TypeLambda, paramNum: Int) - } - /** a self-reference to an enclosing recursive type. */ case class RecThis(binder: RecType) extends BoundType with SingletonType { type BT = RecType override def underlying(implicit ctx: Context) = binder - def copyBoundType(bt: BT)(implicit ctx: Context) = RecThis(bt) + def copyBoundType(bt: BT) = RecThis(bt) // need to customize hashCode and equals to prevent infinite recursion // between RecTypes and RecRefs. diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 8569a609dae1..218ec3f704a3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -409,7 +409,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic => def addTyped(arg: Arg, formal: Type): Type => Type = { addArg(typedArg(arg, formal), formal) if (methodType.isParamDependent) - safeSubstParam(_, methodType.paramRefs.apply(n), typeOfArg(arg)) + safeSubstParam(_, methodType.paramRefs(n), typeOfArg(arg)) else identity } From 184ff8157dee084dd9fff60f91b2aa2461fa1110 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 28 Aug 2017 09:03:17 +0200 Subject: [PATCH 058/146] Make bound types be uniquely created by their binders That way, we don't have to hash cons them. --- .../tools/dotc/core/ConstraintHandling.scala | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 6 +- .../tools/dotc/core/OrderingConstraint.scala | 6 +- .../tools/dotc/core/TypeApplications.scala | 2 +- .../dotty/tools/dotc/core/TypeComparer.scala | 6 +- .../src/dotty/tools/dotc/core/Types.scala | 61 ++++++++++++------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotc/transform/FullParameterization.scala | 2 +- .../dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 6 +- 11 files changed, 59 insertions(+), 40 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 6a98dcf944d2..69f2666d6f18 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -329,7 +329,7 @@ trait ConstraintHandling { checkPropagated(i"initialized $tl") { constraint = constraint.add(tl, tvars) tl.paramNames.indices.forall { i => - val param = TypeParamRef(tl, i) + val param = tl.paramRefs(i) val bounds = constraint.nonParamBounds(param) val lower = constraint.lower(param) val upper = constraint.upper(param) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index c3ee13131fd6..9a8f94e4eff4 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -250,7 +250,7 @@ class Definitions { lazy val Any_## = enterMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final) lazy val Any_getClass = enterMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef.appliedTo(TypeBounds.empty)), Final) lazy val Any_isInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final) - lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, TypeParamRef(_, 0), Final) + lazy val Any_asInstanceOf = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, _.paramRefs(0), Final) lazy val Any_typeTest = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic) // generated by pattern matcher, eliminated by erasure @@ -278,7 +278,7 @@ class Definitions { lazy val Object_eq = enterMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) lazy val Object_ne = enterMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) lazy val Object_synchronized = enterPolyMethod(ObjectClass, nme.synchronized_, 1, - pt => MethodType(List(TypeParamRef(pt, 0)), TypeParamRef(pt, 0)), Final) + pt => MethodType(List(pt.paramRefs(0)), pt.paramRefs(0)), Final) lazy val Object_clone = enterMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected) lazy val Object_finalize = enterMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected) lazy val Object_notify = enterMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType)) @@ -295,7 +295,7 @@ class Definitions { */ lazy val cbnArg = enterPolyMethod( OpsPackageClass, nme.cbnArg, 1, - pt => MethodType(List(FunctionOf(Nil, TypeParamRef(pt, 0))), TypeParamRef(pt, 0))) + pt => MethodType(List(FunctionOf(Nil, pt.paramRefs(0))), pt.paramRefs(0))) /** Method representing a throw */ lazy val throwMethod = enterMethod(OpsPackageClass, nme.THROWkw, diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index b83061e8bc35..279e545cc2bd 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -298,7 +298,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds, val loBuf, hiBuf = new mutable.ListBuffer[TypeParamRef] var i = 0 while (i < poly.paramNames.length) { - val param = TypeParamRef(poly, i) + val param = poly.paramRefs(i) val bounds = nonParamBounds(param) val lo = normalizedType(bounds.lo, loBuf, isUpper = false) val hi = normalizedType(bounds.hi, hiBuf, isUpper = true) @@ -463,12 +463,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds, (poly, entries) <- boundsMap.toList n <- 0 until paramCount(entries) if entries(n).exists - } yield TypeParamRef(poly, n) + } yield poly.paramRefs(n) def forallParams(p: TypeParamRef => Boolean): Boolean = { boundsMap.foreachBinding { (poly, entries) => for (i <- 0 until paramCount(entries)) - if (isBounds(entries(i)) && !p(TypeParamRef(poly, i))) return false + if (isBounds(entries(i)) && !p(poly.paramRefs(i))) return false } true } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 5f25fdfc627a..940ec3c642aa 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -64,7 +64,7 @@ object TypeApplications { } def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match { - case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.toArg)) => Some(fn) + case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.paramRef)) => Some(fn) case _ => None } } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 092cf4ef4132..060eb1708cd5 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -434,7 +434,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2: RecType => def compareRec = tp1.safeDealias match { case tp1: RecType => - val rthis1 = RecThis(tp1) + val rthis1 = tp1.recThis isSubType(tp1.parent, tp2.parent.substRecThis(tp2, rthis1)) case _ => val tp1stable = ensureStableSingleton(tp1) @@ -729,7 +729,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tycon1b = HKTypeLambda(tparams1.map(_.paramName))( tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ - tparams1.indices.toList.map(TypeParamRef(tl, _)))) + tparams1.indices.toList.map(tl.paramRefs(_)))) (ctx.mode.is(Mode.TypevarsMissContext) || tryInstantiate(tycon2, tycon1b.ensureHK)) && isSubType(tp1, tycon1b.appliedTo(args2)) @@ -885,7 +885,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tycon1 = HKTypeLambda(tparams1.map(_.paramName))( tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), tl => tp1base.tycon.appliedTo(args1.take(lengthDiff) ++ - tparams1.indices.toList.map(TypeParamRef(tl, _)))) + tparams1.indices.toList.map(tl.paramRefs(_)))) (ctx.mode.is(Mode.TypevarsMissContext) || tryInstantiate(tycon2, tycon1.ensureHK)) && isSubType(tp1, tycon1.appliedTo(args2)) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6ed2cbeb44a1..53b3d17200df 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -568,7 +568,7 @@ object Types { val rt = if (tp.opened) { // defensive copy tp.openedTwice = true - RecType(rt => tp.parent.substRecThis(tp, RecThis(rt))) + RecType(rt => tp.parent.substRecThis(tp, rt.recThis)) } else tp rt.opened = true try go(rt.parent).mapInfo(_.substRecThis(rt, pre)) @@ -2368,15 +2368,22 @@ object Types { val parent = parentExp(this) + private[this] var myRecThis: RecThis = null + + def recThis: RecThis = { + if (myRecThis == null) myRecThis = new RecThis(this) {} + myRecThis + } + override def underlying(implicit ctx: Context): Type = parent def derivedRecType(parent: Type)(implicit ctx: Context): RecType = if (parent eq this.parent) this - else RecType(rt => parent.substRecThis(this, RecThis(rt))) + else RecType(rt => parent.substRecThis(this, rt.recThis)) def rebind(parent: Type)(implicit ctx: Context): Type = if (parent eq this.parent) this - else RecType.closeOver(rt => parent.substRecThis(this, RecThis(rt))) + else RecType.closeOver(rt => parent.substRecThis(this, rt.recThis)) override def equals(other: Any) = other match { case other: RecType => other.parent == this.parent @@ -2419,7 +2426,7 @@ object Types { val rt = new RecType(parentExp) def normalize(tp: Type): Type = tp.stripTypeVar match { case tp: RecType => - normalize(tp.parent.substRecThis(tp, RecThis(rt))) + normalize(tp.parent.substRecThis(tp, rt.recThis)) case tp @ RefinedType(parent, rname, rinfo) => val rinfo1 = rinfo match { case TypeAlias(TypeRef(RecThis(`rt`), `rname`)) => TypeBounds.empty @@ -2634,7 +2641,7 @@ object Types { def paramNames: List[ThisName] def paramInfos: List[PInfo] def resType: Type - def newParamRef(n: Int): ParamRefType + protected def newParamRef(n: Int): ParamRefType override def resultType(implicit ctx: Context) = resType @@ -2648,7 +2655,12 @@ object Types { final def isTypeLambda = isInstanceOf[TypeLambda] final def isHigherKinded = isInstanceOf[TypeProxy] - lazy val paramRefs: List[ParamRefType] = paramNames.indices.toList.map(newParamRef) + private var myParamRefs: List[ParamRefType] = null + + def paramRefs: List[ParamRefType] = { + if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef) + myParamRefs + } protected def computeSignature(implicit ctx: Context) = resultSignature @@ -2809,7 +2821,7 @@ object Types { */ def isParamDependent(implicit ctx: Context): Boolean = paramDependencyStatus == TrueDeps - def newParamRef(n: Int) = TermParamRef(this, n) + def newParamRef(n: Int) = new TermParamRef(this, n) {} } abstract case class MethodType(paramNames: List[TermName])( @@ -2964,7 +2976,7 @@ object Types { def isDependent(implicit ctx: Context): Boolean = true def isParamDependent(implicit ctx: Context): Boolean = true - def newParamRef(n: Int) = TypeParamRef(this, n) + def newParamRef(n: Int) = new TypeParamRef(this, n) {} lazy val typeParams: List[LambdaParam] = paramNames.indices.toList.map(new LambdaParam(this, _)) @@ -3033,16 +3045,16 @@ object Types { */ def flatten(implicit ctx: Context): PolyType = resType match { case that: PolyType => - val shift = new TypeMap { + val shiftedSubst = (x: PolyType) => new TypeMap { def apply(t: Type) = t match { - case TypeParamRef(`that`, n) => TypeParamRef(that, n + paramNames.length) + case TypeParamRef(`that`, n) => x.paramRefs(n + paramNames.length) case t => mapOver(t) } } PolyType(paramNames ++ that.paramNames)( x => this.paramInfos.mapConserve(_.subst(this, x).bounds) ++ - that.paramInfos.mapConserve(shift(_).subst(that, x).bounds), - x => shift(that.resultType).subst(that, x).subst(this, x)) + that.paramInfos.mapConserve(shiftedSubst(x)(_).bounds), + x => shiftedSubst(x)(that.resultType).subst(this, x)) case _ => this } @@ -3122,8 +3134,7 @@ object Types { def paramInfoAsSeenFrom(pre: Type)(implicit ctx: Context) = paramInfo def paramInfoOrCompleter(implicit ctx: Context): Type = paramInfo def paramVariance(implicit ctx: Context): Int = tl.paramNames(n).variance - def toArg: Type = TypeParamRef(tl, n) - def paramRef(implicit ctx: Context): Type = TypeParamRef(tl, n) + def paramRef(implicit ctx: Context): Type = tl.paramRefs(n) } /** A type application `C[T_1, ..., T_n]` */ @@ -3365,14 +3376,20 @@ object Types { } } - case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { + /** Only created in `binder.paramRefs`. Use `binder.paramRefs(paramNum)` to + * refer to `TermParamRef(binder, paramNum)`. + */ + abstract case class TermParamRef(binder: TermLambda, paramNum: Int) extends ParamRef { type BT = TermLambda - def copyBoundType(bt: BT) = TermParamRef(bt, paramNum) + def copyBoundType(bt: BT) = bt.paramRefs(paramNum) } - case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { + /** Only created in `binder.paramRefs`. Use `binder.paramRefs(paramNum)` to + * refer to `TypeParamRef(binder, paramNum)`. + */ + abstract case class TypeParamRef(binder: TypeLambda, paramNum: Int) extends ParamRef { type BT = TypeLambda - def copyBoundType(bt: BT) = TypeParamRef(bt, paramNum) + def copyBoundType(bt: BT) = bt.paramRefs(paramNum) /** Looking only at the structure of `bound`, is one of the following true? * - fromBelow and param <:< bound @@ -3388,11 +3405,13 @@ object Types { } } - /** a self-reference to an enclosing recursive type. */ - case class RecThis(binder: RecType) extends BoundType with SingletonType { + /** a self-reference to an enclosing recursive type. The only creation method is + * `binder.recThis`, returning `RecThis(binder)`. + */ + abstract case class RecThis(binder: RecType) extends BoundType with SingletonType { type BT = RecType override def underlying(implicit ctx: Context) = binder - def copyBoundType(bt: BT) = RecThis(bt) + def copyBoundType(bt: BT) = bt.recThis // need to customize hashCode and equals to prevent infinite recursion // between RecTypes and RecRefs. diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index cee72f0f33fb..b2d494add104 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -262,7 +262,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi readMethodic(HKTypeLambda, _.toTypeName) case PARAMtype => readTypeRef() match { - case binder: LambdaType => binder.newParamRef(readNat()) + case binder: LambdaType => binder.paramRefs(readNat()) } case CLASSconst => ConstantType(Constant(readType())) @@ -295,7 +295,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case RECtype => RecType(rt => registeringType(rt, readType())) case RECthis => - RecThis(readTypeRef().asInstanceOf[RecType]) + readTypeRef().asInstanceOf[RecType].recThis case SHARED => val ref = readAddr() typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType()) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 70a6a56ce5ec..13d80732d4f4 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -767,7 +767,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (decls.isEmpty) parent else { def subst(info: Type, rt: RecType) = - if (clazz.isClass) info.substThis(clazz.asClass, RecThis(rt)) + if (clazz.isClass) info.substThis(clazz.asClass, rt.recThis) else info // turns out some symbols read into `clazz` are not classes, not sure why this is the case. def addRefinement(tp: Type, sym: Symbol) = RefinedType(tp, sym.name, sym.info) val refined = (parent /: decls.toList)(addRefinement) diff --git a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index d76a41946b39..f3669c845a74 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -113,7 +113,7 @@ trait FullParameterization { /** Replace class type parameters by the added type parameters of the polytype `pt` */ def mapClassParams(tp: Type, pt: PolyType): Type = { val classParamsRange = (mtparamCount until mtparamCount + ctparams.length).toList - tp.substDealias(ctparams, classParamsRange map (TypeParamRef(pt, _))) + tp.substDealias(ctparams, classParamsRange map (pt.paramRefs(_))) } /** The bounds for the added type parameters of the polytype `pt` */ diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 7c1950625e1e..5f71281eaa1a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -391,7 +391,7 @@ object ProtoTypes { for (n <- (0 until tl.paramNames.length).toList) yield { val tt = new TypeTree().withPos(owningTree.pos) - tt.withType(new TypeVar(TypeParamRef(tl, n), state, tt, ctx.owner)) + tt.withType(new TypeVar(tl.paramRefs(n), state, tt, ctx.owner)) } val added = diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 6c435ad222e5..1f25a9d186d3 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -63,7 +63,7 @@ trait TypeAssigner { parent } - def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, RecThis(rt))) + def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, rt.recThis)) val refinableDecls = info.decls.filter( sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor)) @@ -381,7 +381,7 @@ trait TypeAssigner { val newIndex = gapBuf.length gapBuf += idx // Re-index unassigned type arguments that remain after transformation - TypeParamRef(pt, newIndex) + pt.paramRefs(newIndex) } // Type parameters after naming assignment, conserving paramNames order @@ -485,7 +485,7 @@ trait TypeAssigner { else RefinedType(parent, rsym.name, rinfo) } val refined = (parent.tpe /: refinements)(addRefinement) - tree.withType(RecType.closeOver(rt => refined.substThis(refineCls, RecThis(rt)))) + tree.withType(RecType.closeOver(rt => refined.substThis(refineCls, rt.recThis))) } def assignType(tree: untpd.AppliedTypeTree, tycon: Tree, args: List[Tree])(implicit ctx: Context) = { From 5a2c35db0e3552c7d6bdd4776d90900a952f063d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 14:02:48 +0200 Subject: [PATCH 059/146] More detailed stats Mostly used to profile compileStdLib. Stats are about base types and mixin forwarders. --- .../src/dotty/tools/dotc/core/SymDenotations.scala | 6 ++++-- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../src/dotty/tools/dotc/transform/ResolveSuper.scala | 10 ++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index ea22321b08c1..1ac69ad4d8ef 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1670,6 +1670,7 @@ object SymDenotations { } /*>|>*/ ctx.debugTraceIndented(s"$tp.baseType($this)") /*<|<*/ { + Stats.record("baseTypeOf") tp match { case tp: CachedType => val btrCache = baseTypeCache @@ -1679,8 +1680,9 @@ object SymDenotations { btrCache.put(tp, NoPrefix) basetp = computeBaseTypeOf(tp) if (!basetp.exists) Stats.record("base type miss") - if (isCachable(tp, baseTypeCache)) { - if (!basetp.exists) Stats.record("cached base type miss") + if (isCachable(tp, btrCache)) { + if (basetp.exists) Stats.record("cached base type hit") + else Stats.record("cached base type miss") btrCache.put(tp, basetp) } else btrCache.remove(tp) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 53b3d17200df..c86f29b1409c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -848,7 +848,7 @@ object Types { /** The basetype TypeRef of this type with given class symbol, * but without including any type arguments */ - final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("baseType") /*<|<*/ { + final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("base type") /*<|<*/ { base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) case _ => NoType diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 64bcc4a63afd..d8e2414d19c8 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -62,11 +62,17 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th def superAccessors(mixin: ClassSymbol): List[Tree] = for (superAcc <- mixin.info.decls.filter(_.isSuperAccessor).toList) - yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) + yield { + util.Stats.record("super accessors") + polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc))) + } def methodOverrides(mixin: ClassSymbol): List[Tree] = for (meth <- mixin.info.decls.toList if needsForwarder(meth)) - yield polyDefDef(implementation(meth.asTerm), forwarder(meth)) + yield { + util.Stats.record("method forwarders") + polyDefDef(implementation(meth.asTerm), forwarder(meth)) + } val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin)) From 4b34d68bf3429e6cb7dc317aaed69261ef5fd19b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 16:21:24 +0200 Subject: [PATCH 060/146] Fix base type computation Previous algorithm was very slow for compileStdLib, because many intermediate applied typeds were computed. new algorithm computes significantly fewer types. --- .../tools/dotc/core/SymDenotations.scala | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 1ac69ad4d8ef..55be2b0cae5b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1631,8 +1631,10 @@ object SymDenotations { case _: TypeErasure.ErasedValueType => false case tp: TypeRef if tp.symbol.isClass => true case tp: TypeVar => tp.inst.exists && inCache(tp.inst) - case tp: TypeProxy => inCache(tp.underlying) - case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2) + //case tp: TypeProxy => inCache(tp.underlying) // disabled, can re-enable insyead of last two lines for performance testing + //case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2) + case tp: TypeProxy => isCachable(tp.underlying, btrCache) + case tp: AndOrType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache) case _ => true } } @@ -1643,16 +1645,33 @@ object SymDenotations { Stats.record(s"computeBaseType, ${tp.getClass}") } if (symbol.isStatic && tp.derivesFrom(symbol) && symbol.typeParams.isEmpty) - symbol.appliedRef + symbol.typeRef else tp match { - case tp: RefType => - val subcls = tp.symbol - if (subcls eq symbol) - tp - else subcls.denot match { - case cdenot: ClassDenotation => - if (cdenot.baseClassSet contains symbol) foldGlb(NoType, tp.parentsNEW) - else NoType + case tp @ TypeRef(prefix, _) => + val subsym = tp.symbol + if (subsym eq symbol) tp + else subsym.denot match { + case clsd: ClassDenotation => + val owner = clsd.owner + val isOwnThis = prefix match { + case prefix: ThisType => prefix.cls eq owner + case NoPrefix => true + case _ => false + } + if (isOwnThis) + if (clsd.baseClassSet.contains(symbol)) foldGlb(NoType, clsd.classParentsNEW) + else NoType + else + baseTypeOf(clsd.typeRef).asSeenFrom(prefix, owner) + case _ => + baseTypeOf(tp.superType) + } + case tp @ AppliedType(tycon, args) => + val subsym = tycon.typeSymbol + if (subsym eq symbol) tp + else subsym.denot match { + case clsd: ClassDenotation => + baseTypeOf(tycon).subst(clsd.typeParams, args) case _ => baseTypeOf(tp.superType) } @@ -1671,7 +1690,7 @@ object SymDenotations { /*>|>*/ ctx.debugTraceIndented(s"$tp.baseType($this)") /*<|<*/ { Stats.record("baseTypeOf") - tp match { + tp.stripTypeVar match { // @!!! dealias? case tp: CachedType => val btrCache = baseTypeCache try { @@ -1695,7 +1714,7 @@ object SymDenotations { btrCache.put(tp, null) throw ex } - case _ => + case tp => computeBaseTypeOf(tp) } } From 25b9bb05e8105a7003fd798d688322c5967bd2b0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 17:22:30 +0200 Subject: [PATCH 061/146] Fix tests - some tests do deeper subtype recursions, need to be run without -Yno-deep-subtypes - some tests have different outcomes, but the new outcome looks sensible. - some new tests --- compiler/test/dotc/tests.scala | 5 ++--- .../test/dotty/tools/dotc/CompilationTests.scala | 6 ++++++ .../test/dotty/tools/vulpix/TestConfiguration.scala | 1 + tests/neg/leak-type.scala | 6 +++--- .../{customArgs => }/valueclasses-doubledefs2.scala | 2 +- tests/{pos => pos-deep-subtype}/sets.scala | 0 tests/pos/i2974.scala | 12 ++++++++++++ tests/pos/i2982.scala | 8 ++++++++ 8 files changed, 33 insertions(+), 7 deletions(-) rename tests/neg/{customArgs => }/valueclasses-doubledefs2.scala (70%) rename tests/{pos => pos-deep-subtype}/sets.scala (100%) create mode 100644 tests/pos/i2974.scala create mode 100644 tests/pos/i2982.scala diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index a7af432610bd..6b01f2f99d9c 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -104,8 +104,8 @@ class tests extends CompilerTest { val typerDir = dotcDir + "typer/" val libDir = "../library/src/" - def dottyBootedLib = compileDir(libDir, ".", List("-deep", "-Ycheck-reentrant", "-strict") ::: defaultOptions)(allowDeepSubtypes) // note the -deep argument - def dottyDependsOnBootedLib = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant") ::: defaultOptions)(allowDeepSubtypes) // note the -deep argument + def dottyBootedLib = compileDir(libDir, ".", List("-deep", "-Ycheck-reentrant", "-strict"))(allowDeepSubtypes) // note the -deep argument + def dottyDependsOnBootedLib = compileDir(dottyDir, ".", List("-deep", "-Ycheck-reentrant"))(allowDeepSubtypes) // note the -deep argument @Before def cleanup(): Unit = { // remove class files from stdlib and tests compilation @@ -194,7 +194,6 @@ class tests extends CompilerTest { @Test def neg_i1240 = compileFile(negCustomArgs, "i1240")(allowDoubleBindings) @Test def neg_i2002 = compileFile(negCustomArgs, "i2002")(allowDoubleBindings) @Test def neg_valueclasses_doubledefs = compileFile(negCustomArgs, "valueclasses-doubledefs")(allowDoubleBindings) - @Test def neg_valueclasses_doubledefs2 = compileFile(negCustomArgs, "valueclasses-doubledefs2")(allowDoubleBindings) @Test def neg_valueclasses_pavlov = compileFile(negCustomArgs, "valueclasses-pavlov")(allowDoubleBindings) @Test def neg_trailingUnderscore = compileFile(negCustomArgs, "trailingUnderscore", args = "-strict" :: Nil) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index aa0720042eb5..bdff1029eb3d 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -28,6 +28,11 @@ class CompilationTests extends ParallelTesting { // Positive tests ------------------------------------------------------------ + // @Test // enable to test compileStdLib separately with detailed stats + def compileStdLib: Unit = { + compileList("compileStdLib", StdLibSources.whitelisted, scala2Mode.and("-migration", "-Yno-inline", "-Ydetailed-stats")) + }.checkCompile() + @Test def compilePos: Unit = { compileList("compileStdLib", StdLibSources.whitelisted, scala2Mode.and("-migration", "-Yno-inline")) + compileDir("../compiler/src/dotty/tools/dotc/ast", defaultOptions) + @@ -86,6 +91,7 @@ class CompilationTests extends ParallelTesting { compileFilesInDir("../tests/new", defaultOptions) + compileFilesInDir("../tests/pos-scala2", scala2Mode) + compileFilesInDir("../tests/pos", defaultOptions) + + compileFilesInDir("../tests/pos-deep-subtype", allowDeepSubtypes) + compileFile( // succeeds despite -Xfatal-warnings because of -nowarn "../tests/neg/customArgs/xfatalWarnings.scala", diff --git a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala index 7a850c635e26..1c94ba230a10 100644 --- a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala +++ b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala @@ -56,6 +56,7 @@ object TestConfiguration { "-Ytest-pickler", "-Yprintpos" ) + val picklingOptionsAllowDeepSubTypes = picklingOptions without "-Yno-deep-subtypes" val scala2Mode = defaultOptions and "-language:Scala2" val explicitUTF8 = defaultOptions and ("-encoding", "UTF8") val explicitUTF16 = defaultOptions and ("-encoding", "UTF16") diff --git a/tests/neg/leak-type.scala b/tests/neg/leak-type.scala index 30ecab70bcbb..892512c5b025 100644 --- a/tests/neg/leak-type.scala +++ b/tests/neg/leak-type.scala @@ -1,13 +1,13 @@ trait A { - private type Foo = Int + private class Foo - class Inner[T <: Foo] { // error: non-private type T refers to private type Foo in its type signature + class Inner[T <: Foo] { // error: non-private type T refers to private class Foo in its type signature def get: T = ??? } } class B extends A { def foo(x: Inner[_]): Unit = { - val a = x.get // error: cannot resolve reference to type B(B.this).Foo + val a = x.get } } diff --git a/tests/neg/customArgs/valueclasses-doubledefs2.scala b/tests/neg/valueclasses-doubledefs2.scala similarity index 70% rename from tests/neg/customArgs/valueclasses-doubledefs2.scala rename to tests/neg/valueclasses-doubledefs2.scala index dcd7bdf8d444..c4000dfd479d 100644 --- a/tests/neg/customArgs/valueclasses-doubledefs2.scala +++ b/tests/neg/valueclasses-doubledefs2.scala @@ -7,4 +7,4 @@ trait B { def apply(x: Meter) = x.toString } -object Test extends A with B // error: double def +object Test extends A with B // error: double definition diff --git a/tests/pos/sets.scala b/tests/pos-deep-subtype/sets.scala similarity index 100% rename from tests/pos/sets.scala rename to tests/pos-deep-subtype/sets.scala diff --git a/tests/pos/i2974.scala b/tests/pos/i2974.scala new file mode 100644 index 000000000000..75c6a24a41bb --- /dev/null +++ b/tests/pos/i2974.scala @@ -0,0 +1,12 @@ +trait Foo[-T] + +trait Bar[-T] extends Foo[T] + +object Test { + implicit val fa: Foo[Any] = ??? + implicit val ba: Bar[Int] = ??? + + def test: Unit = { + implicitly[Foo[Int]] + } +} diff --git a/tests/pos/i2982.scala b/tests/pos/i2982.scala new file mode 100644 index 000000000000..e4a9bbfad430 --- /dev/null +++ b/tests/pos/i2982.scala @@ -0,0 +1,8 @@ +object A { + def fun[E >: B](a: A[E]): E => Unit = ??? + val x = fun(new A[C]) +} +class B extends C +class C + +class A[-X >: B] From 1daca6ca75f11b1a7681beb74c9d3c1457860784 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 17:51:59 +0200 Subject: [PATCH 062/146] Temporarily disable pattern-matching exhaustivity tests These await the fix by Fenyun. --- compiler/test/dotty/tools/dotc/CompilationTests.scala | 8 ++++---- .../tools/dotc/transform/PatmatExhaustivityTest.scala | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index bdff1029eb3d..c0277730ba8e 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -95,7 +95,7 @@ class CompilationTests extends ParallelTesting { compileFile( // succeeds despite -Xfatal-warnings because of -nowarn "../tests/neg/customArgs/xfatalWarnings.scala", - defaultOptions.and("-nowarn", "-Xfatal-warnings") + defaultOptions //.and("-nowarn", "-Xfatal-warnings") // !!! TODO: re-enable when exchaustivity is fixed ) }.checkCompile() @@ -200,8 +200,8 @@ class CompilationTests extends ParallelTesting { // lower level of concurrency as to not kill their running VMs @Test def testPickling: Unit = { - compileDir("../compiler/src/dotty/tools", picklingOptions) + - compileDir("../compiler/src/dotty/tools/dotc", picklingOptions) + + compileDir("../compiler/src/dotty/tools", picklingOptionsAllowDeepSubTypes) + + compileDir("../compiler/src/dotty/tools/dotc", picklingOptionsAllowDeepSubTypes) + compileFilesInDir("../tests/new", picklingOptions) + compileFilesInDir("../tests/pickling", picklingOptions) + compileDir("../library/src/dotty/runtime", picklingOptions) + @@ -213,7 +213,7 @@ class CompilationTests extends ParallelTesting { compileDir("../compiler/src/dotty/tools/dotc/printing", picklingOptions) + compileDir("../compiler/src/dotty/tools/repl", picklingOptions) + compileDir("../compiler/src/dotty/tools/dotc/rewrite", picklingOptions) + - compileDir("../compiler/src/dotty/tools/dotc/transform", picklingOptions) + + compileDir("../compiler/src/dotty/tools/dotc/transform", picklingOptionsAllowDeepSubTypes) + compileDir("../compiler/src/dotty/tools/dotc/typer", picklingOptions) + compileDir("../compiler/src/dotty/tools/dotc/util", picklingOptions) + compileDir("../compiler/src/dotty/tools/io", picklingOptions) + diff --git a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala index e997ebedd85f..8ea37ee2778e 100644 --- a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala +++ b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala @@ -65,7 +65,8 @@ class PatmatExhaustivityTest { (file, checkContent, actual) } - @Test def patmatExhaustivity: Unit = { + // @Test // TODO: reenable when exchaustivity is fixed + def patmatExhaustivity: Unit = { val res = Directory(testsDir).list.toList .filter(f => f.extension == "scala" || f.isDirectory) .map { f => From 26a327d23821081e23202f0c9af51da925586afb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 17:54:16 +0200 Subject: [PATCH 063/146] Temporarily weaken double definition check A double definition error is now produced in ElimErasedValueType. The reason is that we may generate mixin forwarders in different base classes at non-matching types. The previous implementation of applied types as refinements hid tyhe error by performing the substitutions on access instead of on definition. We should refine the mixin forwarder strategy. Potentially insert them after erasure. Until that is done, the test condition is weakened to make the tests pass. --- .../dotc/transform/ElimErasedValueType.scala | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index d32774243a59..248bf3aaa114 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -86,11 +86,24 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { val site = root.thisType val info1 = site.memberInfo(sym1) val info2 = site.memberInfo(sym2) - if (!info1.matchesLoosely(info2)) + if (!info1.matchesLoosely(info2) && + info1.signature != info2.signature) + // there is a problem here that sometimes we generate too many forwarders. For instance, + // in compileStdLib, compiling scala.immutable.SetProxy, line 29: + // new AbstractSet[B] with SetProxy[B] { val self = newSelf } + // double definition: + // method map: [B, That] + // (f: B => B)(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[B], B, That]): That override in anonymous class scala.collection.AbstractSet[B] with scala.collection.immutable.SetProxy[B]{...} and + // method map: [B, That](f: B => B)(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.Set[B], B, That]): That override in class AbstractSet + // have same type after erasure: (f: Function1, bf: scala.collection.generic.CanBuildFrom): Object + // + // The problem is that `map` was forwarded twice, with different instantiated types. + // It's unclear how to fix this at present (maybe move mixin forwarding after erasure?) + // The added 2nd condition is a rather crude patch. ctx.error( em"""double definition: - |$sym1: $info1 in ${sym1.owner} and - |$sym2: $info2 in ${sym2.owner} + |$sym1: $info1 ${sym1.flags} in ${sym1.owner} and + |$sym2: $info2 ${sym2.flags} in ${sym2.owner} |have same type after erasure: $info""", root.pos) } From 95720b05b5ecbe6ee797e3d3151b071d64010b95 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 29 Aug 2017 17:55:30 +0200 Subject: [PATCH 064/146] Temporarily existentials test to pending Existentials.scala tests several different un-reducibility conditions, but right now only one of them triggers. Needs to be re-enabled after further investigation. --- tests/{ => pending}/neg/existentials.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{ => pending}/neg/existentials.scala (96%) diff --git a/tests/neg/existentials.scala b/tests/pending/neg/existentials.scala similarity index 96% rename from tests/neg/existentials.scala rename to tests/pending/neg/existentials.scala index 351febc7949b..a553656729a4 100644 --- a/tests/neg/existentials.scala +++ b/tests/pending/neg/existentials.scala @@ -44,7 +44,7 @@ class TestX { type D[X] <: C[X] type DD = [X] => D[D[X]] - val z: DD[_] = ??? // error: unreducible + //val z: DD[_] = ??? // error: unreducible val g = x.get From 3c4b6bd0a28cda7b0c3ce42219a969d3b78ba43f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 30 Aug 2017 19:07:00 +0200 Subject: [PATCH 065/146] Ensure type correctness of repeated arguments Make sure elimRepeated produces array arguments that match the formal parameter type. Previously, there was a gap which showed itself when compiling scala/concurrent/forkjoin/package.scala There, the method expected a repeated argument of type ForkJoinTask[_], so the expected type was Array[ForkJoinTask[_]]. But the type computed by seqToArray was Array[ForkJoinTask[T]]. Since arrays are non-variant, these types are not compatible! This somehow slipped through with the previous implementation of applied types. --- .../tools/dotc/transform/ElimRepeated.scala | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 1a05dc9f48b8..60da2e7c33b6 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -11,6 +11,7 @@ import Flags._ import Contexts.Context import Symbols._ import Constants._ +import Decorators._ import Denotations._, SymDenotations._ import Decorators.StringInterpolators import dotty.tools.dotc.ast.tpd @@ -73,18 +74,23 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati transformTypeOfTree(tree) override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = { - val args1 = tree.args.map { - case arg: Typed if isWildcardStarArg(arg) => - if (tree.fun.symbol.is(JavaDefined) && arg.expr.tpe.derivesFrom(defn.SeqClass)) - seqToArray(arg.expr) - else arg.expr - case arg => arg + val formals = (tree.fun.tpe.widen: @unchecked) match { + case mt: MethodType => mt.paramInfos + } + val args1 = tree.args.zipWithConserve(formals) { (arg, formal) => + arg match { + case arg: Typed if isWildcardStarArg(arg) => + if (tree.fun.symbol.is(JavaDefined) && arg.expr.tpe.derivesFrom(defn.SeqClass)) + seqToArray(arg.expr, formal.translateParameterized(defn.RepeatedParamClass, defn.ArrayClass)) + else arg.expr + case arg => arg + } } transformTypeOfTree(cpy.Apply(tree)(tree.fun, args1)) } - /** Convert sequence argument to Java array */ - private def seqToArray(tree: Tree)(implicit ctx: Context): Tree = tree match { + /** Convert sequence argument to Java array of type `pt` */ + private def seqToArray(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match { case SeqLiteral(elems, elemtpt) => JavaSeqLiteral(elems, elemtpt) case _ => @@ -95,7 +101,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati .select(nme.seqToArray) .appliedToType(elemType) .appliedTo(tree, Literal(Constant(elemClass.typeRef))) - .ensureConforms(defn.ArrayOf(elemType)) + .ensureConforms(pt) // Because of phantomclasses, the Java array's type might not conform to the return type } From 41d6d9eaca11b098f645e2437769d0c0c7b05fdd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 30 Aug 2017 22:46:20 +0200 Subject: [PATCH 066/146] Update "good bounds" checks These need to be special-cased for base types now, since conflicting base types do not need any longer to public type members with conflicting bounds. A Test case where this shows up is points.scala. Another is Iter3.scala which got moved from pos to neg. These test cases passed in the old scheme, probably because comflicting aliases were not coalesced into bad type bounds. points.scala failed at ElimErasedValueTypes because it reported a double definition, but I think that one was not correct either and came from the same root cause of conflicting aliases. --- .../tools/dotc/core/CheckRealizable.scala | 42 +++++++++++++++---- .../src/dotty/tools/dotc/typer/Checking.scala | 6 +-- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/{pos => neg}/Iter3.scala | 6 +-- tests/neg/points.scala | 16 +++++-- 5 files changed, 53 insertions(+), 19 deletions(-) rename tests/{pos => neg}/Iter3.scala (96%) diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala index 78ec685fc114..67ff6f505335 100644 --- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -33,6 +33,12 @@ object CheckRealizable { class HasProblemBounds(typ: SingleDenotation)(implicit ctx: Context) extends Realizability(i" has a member $typ with possibly conflicting bounds ${typ.info.bounds.lo} <: ... <: ${typ.info.bounds.hi}") + class HasProblemBaseArg(typ: Type, argBounds: TypeBounds)(implicit ctx: Context) + extends Realizability(i" has a base type $typ with possibly conflicting parameter bounds ${argBounds.lo} <: ... <: ${argBounds.hi}") + + class HasProblemBase(base1: Type, base2: Type)(implicit ctx: Context) + extends Realizability(i" has conflicting base types $base1 and $base2") + class HasProblemField(fld: SingleDenotation, problem: Realizability)(implicit ctx: Context) extends Realizability(i" has a member $fld which is not a legal path\n since ${fld.symbol.name}: ${fld.info}${problem.msg}") @@ -89,18 +95,36 @@ class CheckRealizable(implicit ctx: Context) { else boundsRealizability(tp).andAlso(memberRealizability(tp)) } - /** `Realizable` if `tp` has good bounds, a `HasProblemBounds` instance - * pointing to a bad bounds member otherwise. + /** `Realizable` if `tp` has good bounds, a `HasProblem...` instance + * pointing to a bad bounds member otherwise. "Has good bounds" means: + * + * - all type members have good bounds + * - all base types are class types, and if their arguments are wildcards + * they have good bounds. */ private def boundsRealizability(tp: Type) = { - def hasBadBounds(mbr: SingleDenotation) = { - val bounds = mbr.info.bounds - !(bounds.lo <:< bounds.hi) - } - tp.nonClassTypeMembers.find(hasBadBounds) match { - case Some(mbr) => new HasProblemBounds(mbr) - case _ => Realizable + val mbrProblems = + for { + mbr <- tp.nonClassTypeMembers + if !(mbr.info.loBound <:< mbr.info.hiBound) + } + yield new HasProblemBounds(mbr) + + def baseTypeProblems(base: Type) = base match { + case AndType(base1, base2) => + new HasProblemBase(base1, base2) :: Nil + case base => + base.argInfos.collect { + case bounds @ TypeBounds(lo, hi) if !(lo <:< hi) => + new HasProblemBaseArg(base, bounds) + } } + val baseProblems = + tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems) + + (((Realizable: Realizability) + /: mbrProblems)(_ andAlso _) + /: baseProblems)(_ andAlso _) } /** `Realizable` if all of `tp`'s non-struct fields have realizable types, diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index e98bb525b63c..c065d5ab12ef 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -551,10 +551,10 @@ trait Checking { if (!tp.isStable) ctx.error(ex"$tp is not stable", pos) /** Check that all type members of `tp` have realizable bounds */ - def checkRealizableBounds(tp: Type, pos: Position)(implicit ctx: Context): Unit = { - val rstatus = boundsRealizability(tp) + def checkRealizableBounds(cls: Symbol, pos: Position)(implicit ctx: Context): Unit = { + val rstatus = boundsRealizability(cls.thisType) if (rstatus ne Realizable) - ctx.error(ex"$tp cannot be instantiated since it${rstatus.msg}", pos) + ctx.error(ex"$cls cannot be instantiated since it${rstatus.msg}", pos) } /** Check that `tp` is a class type. diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c429771a5c00..e66201316cc0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1413,7 +1413,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit .withType(dummy.nonMemberTermRef) checkVariance(impl1) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) - checkRealizableBounds(cls.thisType, cdef.namePos) // !@@@ adapt + checkRealizableBounds(cls, cdef.namePos) // !@@@ adapt val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls) if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) diff --git a/tests/pos/Iter3.scala b/tests/neg/Iter3.scala similarity index 96% rename from tests/pos/Iter3.scala rename to tests/neg/Iter3.scala index d0ae79f1f213..68dfdc1ac6de 100644 --- a/tests/pos/Iter3.scala +++ b/tests/neg/Iter3.scala @@ -59,19 +59,19 @@ object Iter2 { if (isEmpty) 0 else 1 + tail.length } - case class Cons[A](x: A, xs: List[A]) extends List[A] { + case class Cons[A](x: A, xs: List[A]) extends List[A] { // error: cannot be instantiated def isEmpty = false def head = x def tail = xs } - case object Nil extends List[Nothing] { + case object Nil extends List[Nothing] { // error: cannot be instantiated def isEmpty = true def head = ??? def tail = ??? } - class ArrayBuffer[A] private (initElems: Array[AnyRef], initLen: Int) extends Seq[A] with FromIterator[ArrayBuffer] { + class ArrayBuffer[A] private (initElems: Array[AnyRef], initLen: Int) extends Seq[A] with FromIterator[ArrayBuffer] { // error: cannot be instantiated def this() = this(new Array[AnyRef](16), 0) def this(it: ArrayIterator[A]) = this(it.elems, it.len) private var elems: Array[AnyRef] = initElems diff --git a/tests/neg/points.scala b/tests/neg/points.scala index e642fd737e76..e5a48e8de0a6 100644 --- a/tests/neg/points.scala +++ b/tests/neg/points.scala @@ -1,8 +1,18 @@ +trait Comparable[T] { + def compareTo(other: T): Int +} + class Point extends Comparable[Point] { - override def compareTo(other: Point): Int = ??? + override def compareTo(other: Point): Int = 1 } -class ColoredPoint extends Point with Comparable[ColoredPoint] { - override def compareTo(other: ColoredPoint): Int = ??? // error: overridden method has different signature +class ColoredPoint extends Point with Comparable[ColoredPoint] { // error: cannot be instantiated + override def compareTo(other: ColoredPoint): Int = -1 } +object Test extends App { + val c: Point = new ColoredPoint + def cmp[T <: Comparable[T]](p1: Comparable[T], p2: T) = + p1.compareTo(p2) + println(cmp(c, c)) +} From 88953fa58a8b778c0cd494ec408745ccddcb46fd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 10:01:38 +0200 Subject: [PATCH 067/146] Exclude mixin forwarders from double definition checks With the new applied type scheme, we can generate mixin forwarders for the same method at different base types which end up with different types if the base types have different type arguments. This can lead to spurious "double definition with same erased type" failures, if these instantiations do not have matching types. --- .../dotc/transform/ElimErasedValueType.scala | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 248bf3aaa114..6f091fee2683 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -86,20 +86,21 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { val site = root.thisType val info1 = site.memberInfo(sym1) val info2 = site.memberInfo(sym2) - if (!info1.matchesLoosely(info2) && - info1.signature != info2.signature) - // there is a problem here that sometimes we generate too many forwarders. For instance, - // in compileStdLib, compiling scala.immutable.SetProxy, line 29: + def isDefined(sym: Symbol) = sym.initialDenot.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: // new AbstractSet[B] with SetProxy[B] { val self = newSelf } - // double definition: + // This generates two forwarders, one in AbstractSet, the other in the anonymous class itself. + // Their signatures are: // method map: [B, That] // (f: B => B)(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.immutable.Set[B], B, That]): That override in anonymous class scala.collection.AbstractSet[B] with scala.collection.immutable.SetProxy[B]{...} and // method map: [B, That](f: B => B)(implicit bf: scala.collection.generic.CanBuildFrom[scala.collection.Set[B], B, That]): That override in class AbstractSet - // have same type after erasure: (f: Function1, bf: scala.collection.generic.CanBuildFrom): Object + // These have same type after erasure: + // (f: Function1, bf: scala.collection.generic.CanBuildFrom): Object // // The problem is that `map` was forwarded twice, with different instantiated types. - // It's unclear how to fix this at present (maybe move mixin forwarding after erasure?) - // The added 2nd condition is a rather crude patch. + // Maybe we should move mixin forwarding after erasure to avoid redundant forwarders like these. ctx.error( em"""double definition: |$sym1: $info1 ${sym1.flags} in ${sym1.owner} and From 77077a5110840ca1a97462b1ba1bdea5f16bdaf6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 10:42:35 +0200 Subject: [PATCH 068/146] Adapt superclass inference to new scheme It could now be that a superclass type is an AndType of two class types. This case needs to be rejected and healed. Test case is templateParents.scala, which crashed without the fix in this commit. --- .../src/dotty/tools/dotc/typer/Checking.scala | 15 +++++++++------ compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Typer.scala | 15 ++++++--------- tests/neg/templateParents.scala | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index c065d5ab12ef..844695582729 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -584,12 +584,15 @@ trait Checking { case _ => } - /** Check that any top-level type arguments in this type are feasible, i.e. that - * their lower bound conforms to their upper bound. If a type argument is - * infeasible, issue and error and continue with upper bound. + /** Check that `tp` is a class type and that any top-level type arguments in this type + * are feasible, i.e. that their lower bound conforms to their upper bound. If a type + * argument is infeasible, issue and error and continue with upper bound. */ - def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = + def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match { + case tp @ AndType(tp1, tp2) => + ctx.error(s"conflicting type arguments$where", pos) + tp1 case tp @ AppliedType(tycon, args) => def checkArg(arg: Type) = arg match { case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => @@ -599,7 +602,7 @@ trait Checking { } tp.derivedAppliedType(tycon, args.mapConserve(checkArg)) case tp: RefinedType => // @!!! - tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where)) + tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasibleParent(tp.refinedInfo, pos, where)) case tp: RecType => // @!!! tp.rebind(tp.parent) case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => // @!!! @@ -749,7 +752,7 @@ trait NoChecking extends Checking { override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = () override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () - override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp + override def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = () override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = () override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = () diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 06f889c66132..836133883789 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -913,7 +913,7 @@ class Namer { typer: Typer => indexAndAnnotate(rest)(inClassContext(selfInfo)) symbolOfTree(constr).ensureCompleted() - val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_))) + val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)), cls.pos) val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls) typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %, parentRefs = $parentRefs%, %") diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index e66201316cc0..cd50fb743361 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1394,7 +1394,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit completeAnnotations(cdef, cls) val constr1 = typed(constr).asInstanceOf[DefDef] - val parentsWithClass = ensureFirstIsClass(parents mapconserve typedParent, cdef.namePos) + val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.namePos) val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx) val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible if (self1.tpt.tpe.isError || classExistsOnSelf(cls.unforcedDecls, self1)) { @@ -1451,7 +1451,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit * - has C as its class symbol, and * - for all parents P_i: If P_i derives from C then P_i <:< CT. */ - def ensureFirstIsClass(parents: List[Type])(implicit ctx: Context): List[Type] = { + def ensureFirstIsClass(parents: List[Type], pos: Position)(implicit ctx: Context): List[Type] = { def realClassParent(cls: Symbol): ClassSymbol = if (!cls.isClass) defn.ObjectClass else if (!(cls is Trait)) cls.asClass @@ -1468,19 +1468,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case _ => val pcls = (defn.ObjectClass /: parents)(improve) typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %") - val ptype = ctx.typeComparer.glb( + val first = ctx.typeComparer.glb( defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls))) - ptype :: parents + checkFeasibleParent(first, pos, em" in inferred superclass $first") :: parents } } /** Ensure that first parent tree refers to a real class. */ - def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match { + def ensureFirstTreeIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match { case p :: ps if p.tpe.classSymbol.isRealClass => parents - case _ => - // add synthetic class type - val first :: _ = ensureFirstIsClass(parents.tpes) - TypeTree(checkFeasible(first, pos, em"\n in inferred parent $first")).withPos(pos) :: parents + case _ => TypeTree(ensureFirstIsClass(parents.tpes, pos).head).withPos(pos) :: parents } /** If this is a real class, make sure its first parent is a diff --git a/tests/neg/templateParents.scala b/tests/neg/templateParents.scala index a039625254eb..0ee134d2f594 100644 --- a/tests/neg/templateParents.scala +++ b/tests/neg/templateParents.scala @@ -12,5 +12,5 @@ object templateParentsNeg1 { trait D extends C[String] trait E extends C[Int] - val x = new D with E // error no type fits between inferred bounds + val x = new D with E // error: conflicting type arguments inferred type } From 89d9ef9843ad8b74b11cd7bc050bed8d58091cf1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 10:55:19 +0200 Subject: [PATCH 069/146] Avoid inifinite loop when comparing & types with class types The problem is that in two cases of subtype checking we form the base type of the lhs, and, if that yields a new type continue with that one. But this is not enough to ensure progress. Concrete test cases were in `run/mixins1` and pos/intersections.scala. In `mixins1` we had an infinite cycle in the situation A[LazyRef(This)] & B <: A[B] where `This <: A[This]` and `B extended A[B]`. We got `A[LazyRef(This)] & A[B]` as a base type, which simplified to `A[_ >: LayzRef(This) | B <: LazyRef(This) & B]`. Then, subsequent base types cycled back and forth until the original type was reached. The change in TypeComparer avoids the simplification (which is really a complication) and keeps instead ``A[LazyRef(This)] & A[B]`. We then need the change in SymDenotations to make sure that the base type of this type wrt `A` is referentially the same type, so that we avoid the loop. I wish there was a more robust measure for determining whether taking a base type represents progress. --- .../tools/dotc/core/SymDenotations.scala | 12 ++++++++--- .../dotty/tools/dotc/core/TypeComparer.scala | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 55be2b0cae5b..edd28cbd006a 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1633,7 +1633,7 @@ object SymDenotations { case tp: TypeVar => tp.inst.exists && inCache(tp.inst) //case tp: TypeProxy => inCache(tp.underlying) // disabled, can re-enable insyead of last two lines for performance testing //case tp: AndOrType => inCache(tp.tp1) && inCache(tp.tp2) - case tp: TypeProxy => isCachable(tp.underlying, btrCache) + case tp: TypeProxy => isCachable(tp.underlying, btrCache) case tp: AndOrType => isCachable(tp.tp1, btrCache) && isCachable(tp.tp2, btrCache) case _ => true } @@ -1678,9 +1678,15 @@ object SymDenotations { case tp: TypeProxy => baseTypeOf(tp.superType) case AndType(tp1, tp2) => - baseTypeOf(tp1) & baseTypeOf(tp2) + baseTypeOf(tp1) & baseTypeOf(tp2) match { + case AndType(tp1a, tp2a) if (tp1a eq tp1) && (tp2a eq tp2) => tp + case res => res + } case OrType(tp1, tp2) => - baseTypeOf(tp1) | baseTypeOf(tp2) + baseTypeOf(tp1) | baseTypeOf(tp2) match { + case OrType(tp1a, tp2a) if (tp1a eq tp1) && (tp2a eq tp2) => tp + case res => res + } case JavaArrayType(_) if symbol == defn.ObjectClass => this.typeRef case _ => diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 060eb1708cd5..6a26a7880d92 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1448,10 +1448,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val arg2 :: args2Rest = args2 val v = tparam.paramVariance val glbArg = - if (v > 0) glb(arg1.hiBound, arg2.hiBound) + if (isSameTypeWhenFrozen(arg1, arg2)) arg1 + else if (v > 0) glb(arg1.hiBound, arg2.hiBound) else if (v < 0) lub(arg1.loBound, arg2.loBound) - else TypeBounds(lub(arg1.loBound, arg2.loBound), - glb(arg1.hiBound, arg2.hiBound)) + else if (arg1.isInstanceOf[TypeBounds] || arg2.isInstanceOf[TypeBounds]) + TypeBounds(lub(arg1.loBound, arg2.loBound), + glb(arg1.hiBound, arg2.hiBound)) + else NoType glbArg :: glbArgs(args1Rest, args2Rest, tparamsRest) case nil => Nil @@ -1599,7 +1602,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1 @ AppliedType(tycon1, args1) => tp2 match { case AppliedType(tycon2, args2) if tycon1.typeSymbol == tycon2.typeSymbol => - (tycon1 & tycon2).appliedTo(glbArgs(args1, args2, tycon1.typeParams)) + val jointArgs = glbArgs(args1, args2, tycon1.typeParams) + if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs) + else NoType case _ => NoType } @@ -1730,15 +1735,17 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** Show subtype goal that led to an assertion failure */ def showGoal(tp1: Type, tp2: Type)(implicit ctx: Context) = { - println(ex"assertion failure for $tp1 <:< $tp2, frozen = $frozenConstraint") + println(i"assertion failure for $tp1 <:< $tp2, frozen = $frozenConstraint") def explainPoly(tp: Type) = tp match { case tp: TypeParamRef => ctx.echo(s"TypeParamRef ${tp.show} found in ${tp.binder.show}") case tp: TypeRef if tp.symbol.exists => ctx.echo(s"typeref ${tp.show} found in ${tp.symbol.owner.show}") case tp: TypeVar => ctx.echo(s"typevar ${tp.show}, origin = ${tp.origin}") case _ => ctx.echo(s"${tp.show} is a ${tp.getClass}") } - explainPoly(tp1) - explainPoly(tp2) + if (Config.verboseExplainSubtype) { + explainPoly(tp1) + explainPoly(tp2) + } } /** Record statistics about the total number of subtype checks From 6f49cfdbad9e654676d12c096fb98b115f9d0f20 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 11:37:22 +0200 Subject: [PATCH 070/146] Fix rebase breakage --- compiler/src/dotty/tools/dotc/Run.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotty/tools/repl/UserFacingPrinter.scala | 148 ++++++++++++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 repl/src/dotty/tools/repl/UserFacingPrinter.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index e0044268a6d9..ebf16bb9eb14 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -105,7 +105,7 @@ class Run(comp: Compiler, ictx: Context) { compileUnits()(ctx) } - protected def compileUnits()(implicit ctx: Context) = Stats.monitorHeartBeat { + protected def compileUnits()(implicit ctx: Context) = Stats.maybeMonitored { ctx.checkSingleThreaded() // If testing pickler, make sure to stop after pickling phase: diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c86f29b1409c..9e5abe2145b3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -153,7 +153,7 @@ object Types { } def isInfixType(implicit ctx: Context): Boolean = this match { - case TypeApplications.AppliedType(tycon, args) => + case TypeApplications.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 diff --git a/repl/src/dotty/tools/repl/UserFacingPrinter.scala b/repl/src/dotty/tools/repl/UserFacingPrinter.scala new file mode 100644 index 000000000000..3b020ef94c02 --- /dev/null +++ b/repl/src/dotty/tools/repl/UserFacingPrinter.scala @@ -0,0 +1,148 @@ +package dotty.tools +package repl + +import dotc.ast.Trees.{ Untyped, Tree } +import dotc.core.Annotations.Annotation +import dotc.core.Constants.Constant +import dotc.core.Contexts.Context +import dotc.core.Denotations.{ Denotation, MultiDenotation, SingleDenotation } +import dotc.core.Flags._ +import dotc.core.TypeApplications.{ AnyAppliedType, EtaExpansion } +import dotc.core.Names._ +import dotc.core.NameOps._ +import dotc.core.StdNames._ +import dotc.core.Decorators._ +import dotc.core.Scopes.Scope +import dotc.core.Symbols.{ Symbol, ClassSymbol, defn } +import dotc.core.SymDenotations.NoDenotation +import dotc.core.Types._ +import dotc.printing.Texts._ +import dotc.printing.{ GlobalPrec, DotPrec, Printer, PlainPrinter } +import dotc.typer.Implicits.SearchResult +import dotc.typer.ImportInfo + +class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { + + private def panic(msg: String): Nothing = throw new AssertionError(msg) + + private[this] def getPkgCls(path: String) = + _ctx.requiredPackage(path).moduleClass.asClass + + private lazy val collectionPkg = getPkgCls("scala.collection") + private lazy val immutablePkg = getPkgCls("scala.collection.immutable") + private lazy val scalaPkg = defn.ScalaPackageClass + private lazy val javaLangPkg = defn.JavaLangPackageVal.moduleClass.asClass + + def standardPkg(pkgSym: Symbol) = pkgSym match { + case `scalaPkg` | `collectionPkg` | `immutablePkg` | `javaLangPkg` => true + case _ => false + } + + def wrappedName(pkgSym: Symbol) = + pkgSym.name.toTermName == nme.EMPTY_PACKAGE || + pkgSym.name.isReplWrapperName + + def wellKnownPkg(pkgSym: Symbol) = standardPkg(pkgSym) || wrappedName(pkgSym) + + override protected def keyString(sym: Symbol): String = { + val flags = sym.flags + if (flags is Package) "" + else if (sym.isPackageObject) "package object" + else if (flags.is(Module) && flags.is(Case)) "case object" + else if (sym.isClass && flags.is(Case)) "case class" + else if (flags.is(Lazy)) "lazy val" + else if (flags is Module) "object" + else if (sym.isTerm && !flags.is(Param) && flags.is(Implicit)) "implicit val" + else super.keyString(sym) + } + + override def nameString(name: Name): String = + if (name.isReplAssignName) name.decode.toString.takeWhile(_ != '$') + else name.decode.toString + + override def toText(sym: Symbol): Text = + if (sym.name.isReplAssignName) nameString(sym.name) + else keyString(sym) ~~ nameString(sym.name.stripModuleClassSuffix) + + override def dclText(sym: Symbol): Text = + toText(sym) ~ { + if (sym.is(Method)) toText(sym.info) + else if (sym.isClass) "" + else if (sym.isType && sym.info.isInstanceOf[TypeAlias]) " =" ~~ toText(sym.info) + else if (sym.isType) "" + else { + ":" ~~ toText(sym.info) + } + } + + override def toText(denot: Denotation): Text = denot match { + case NoDenotation => + panic("NoDenotation encountered in UserFacingPrinter") + case denot: MultiDenotation => + panic("MultiDenotation not allowed in UserFacingPrinter") + case _ => + toText(denot.symbol) + } + + override def toText(const: Constant): Text = Str(const.value.toString) + + override def toText(tp: Type): Text = tp match { + case tp: AnnotatedType => toText(tp.tpe) ~~ toText(tp.annot) + case tp: ConstantType => toText(tp.value) + case tp: TypeAlias => toText(tp.underlying) + case ExprType(result) => ":" ~~ toText(result) + case TypeBounds(lo, hi) => + { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ + { if (hi != defn.AnyType) "<:" ~~ toText(hi) else Text() } + case tp: TypeRef => tp.info match { + case TypeAlias(alias) => toText(alias) + case _ => toText(tp.info) + } + case tp: ParamRef => { + val name = tp.paramName.unexpandedName.invariantName.toString + if (tp.isInstanceOf[TermParamRef]) name ~ ".type" + else name + } + case EtaExpansion(tycon) => toText(tycon) + case PolyType(params, res) => + "[" ~ Fluid(params.map(tl => toText(tl.paramRef)).intersperse(Str(", "))) ~ "]" ~ toText(res) + case tp: MethodType => { + def paramText(name: TermName, tp: Type) = toText(name) ~ ": " ~ toText(tp) + changePrec(GlobalPrec) { + (if (tp.isImplicit) "(implicit " else "(") ~ + Text((tp.paramNames, tp.paramInfos).zipped map paramText, ", ") ~ + (if (tp.resultType.isInstanceOf[MethodType]) ")" else "): ") ~ + toText(tp.resultType) + } + } + case AnyAppliedType(tycon, args) => { + def toTextInfixType(tycon: Type, args: List[Type]): Text = { + // TODO: blatant copy from `RefinedPrinter` + val l :: r :: Nil = args + val isRightAssoc = tycon.typeSymbol.name.endsWith(":") + val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ toText(l) ~ ")" else toText(l) + val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ toText(r) ~ ")" else toText(r) + leftArg ~~ atPrec(DotPrec) { tycon.toText(this) } ~~ rightArg + } + if (tp.isInfixType) toTextInfixType(tycon, args) + else { + toText(tycon) ~ "[" ~ Fluid(args.reverse.map(toText).intersperse(Str(", "))) ~ "]" + } + } + case tp: ClassInfo => { + if (wellKnownPkg(tp.cls.owner)) + nameString(tp.cls.name) + else { + def printPkg(sym: ClassSymbol): Text = + if (sym.owner == defn.RootClass || wrappedName(sym.owner)) + nameString(sym.name.stripModuleClassSuffix) + else + printPkg(sym.owner.asClass) ~ "." ~ toText(sym) + + printPkg(tp.cls.owner.asClass) ~ "." ~ nameString(tp.cls.name) + } + } + } + + override lazy val plain = new PlainPrinter(_ctx) +} From e631f381a534786806599904a91a23f5bc3fd8f1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 13:19:41 +0200 Subject: [PATCH 071/146] Handle TypeArgRefs in UserfacingPrinter --- .../dotty/tools/repl/UserFacingPrinter.scala | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/repl/src/dotty/tools/repl/UserFacingPrinter.scala b/repl/src/dotty/tools/repl/UserFacingPrinter.scala index 3b020ef94c02..909c0225085b 100644 --- a/repl/src/dotty/tools/repl/UserFacingPrinter.scala +++ b/repl/src/dotty/tools/repl/UserFacingPrinter.scala @@ -21,6 +21,7 @@ import dotc.printing.{ GlobalPrec, DotPrec, Printer, PlainPrinter } import dotc.typer.Implicits.SearchResult import dotc.typer.ImportInfo +// TODO: Avoid code duplication between userfacing and refined printers class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { private def panic(msg: String): Nothing = throw new AssertionError(msg) @@ -92,7 +93,7 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case tp: TypeAlias => toText(tp.underlying) case ExprType(result) => ":" ~~ toText(result) case TypeBounds(lo, hi) => - { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ + { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ // TODO: that's different from how args are written in source! { if (hi != defn.AnyType) "<:" ~~ toText(hi) else Text() } case tp: TypeRef => tp.info match { case TypeAlias(alias) => toText(alias) @@ -116,19 +117,28 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } } case AnyAppliedType(tycon, args) => { + def argText(tp: Type) = + toText { + tp match { + case tp: TypeArgRef => tp.underlying + case _ => tp + } + } def toTextInfixType(tycon: Type, args: List[Type]): Text = { // TODO: blatant copy from `RefinedPrinter` val l :: r :: Nil = args val isRightAssoc = tycon.typeSymbol.name.endsWith(":") - val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ toText(l) ~ ")" else toText(l) - val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ toText(r) ~ ")" else toText(r) + val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ argText(l) ~ ")" else argText(l) + val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ argText(r) ~ ")" else argText(r) leftArg ~~ atPrec(DotPrec) { tycon.toText(this) } ~~ rightArg } if (tp.isInfixType) toTextInfixType(tycon, args) else { - toText(tycon) ~ "[" ~ Fluid(args.reverse.map(toText).intersperse(Str(", "))) ~ "]" + toText(tycon) ~ "[" ~ Fluid(args.reverse.map(argText).intersperse(Str(", "))) ~ "]" } } + case tp: TypeArgRef => + super.toText(tp) case tp: ClassInfo => { if (wellKnownPkg(tp.cls.owner)) nameString(tp.cls.name) From c3d44d7191208db211b0cbb6fbe7cb1034ff4cef Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 13:20:15 +0200 Subject: [PATCH 072/146] Fix imports and add explanations in Space --- .../dotty/tools/dotc/transform/patmat/Space.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 63db4da5a59b..fa4a707c7bdb 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -577,6 +577,18 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { case _ => tp2 } +/** This might be useful for adapting to the new applied type scheme: */ + + import TypeApplications._ + import typer.ProtoTypes.constrained + import ast.untpd + + /** If `clsRef` is a subclass of `tp1`, the largest class type of the form + * + * pre.[args] + * + * which is a subtype of `tp1`. + */ def derivingType(tp1: AppliedType, clsRef: TypeRef): Type = { val cls = clsRef.symbol val typeParams = cls.typeParams From 812373f0adb8575f02426ead66a64be403381223 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 15:47:02 +0200 Subject: [PATCH 073/146] Eliminate Config switches We are going to dismantle the old scheme code, so no need to keep the switches. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 20 +--- compiler/src/dotty/tools/dotc/ast/tpd.scala | 15 +-- .../src/dotty/tools/dotc/config/Config.scala | 3 - .../src/dotty/tools/dotc/core/Contexts.scala | 4 +- .../dotty/tools/dotc/core/Denotations.scala | 3 +- .../src/dotty/tools/dotc/core/Flags.scala | 4 +- .../tools/dotc/core/TypeApplications.scala | 97 ++----------------- .../dotty/tools/dotc/core/TypeComparer.scala | 19 +--- .../src/dotty/tools/dotc/core/TypeOps.scala | 51 +--------- .../src/dotty/tools/dotc/core/Types.scala | 60 ++++-------- .../dotc/core/classfile/ClassfileParser.scala | 17 +--- .../core/unpickleScala2/Scala2Unpickler.scala | 5 +- .../tools/dotc/transform/patmat/Space.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 4 +- .../src/dotty/tools/dotc/typer/Checking.scala | 8 -- .../dotty/tools/dotc/typer/Implicits.scala | 8 +- 16 files changed, 46 insertions(+), 274 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 3b103071cdc1..eded1a5b7693 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -238,23 +238,6 @@ object desugar { Nil } - /** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows: - * - * class C[v T] - * ==> - * class C { type v C$T; type v T = C$T } - */ - def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = { - if (tdef.mods.is(PrivateLocalParam) && !dotty.tools.dotc.config.Config.newScheme) { - val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner)) - .withMods(tdef.mods &~ PrivateLocal) - val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam)) - .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic) - Thicket(tparam, alias) - } - else tdef - } - @sharable private val synthetic = Modifiers(Synthetic) private def toDefParam(tparam: TypeDef): TypeDef = @@ -696,7 +679,7 @@ object desugar { def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match { case tree: ValDef => valDef(tree) - case tree: TypeDef => if (tree.isClassDef) classDef(tree) else typeDef(tree) + case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree case tree: DefDef => defDef(tree) case tree: ModuleDef => moduleDef(tree) case tree: PatDef => patDef(tree) @@ -1133,7 +1116,6 @@ object desugar { def refinedTypeToClass(parent: tpd.Tree, refinements: List[Tree])(implicit ctx: Context): TypeDef = { def stripToCore(tp: Type): List[Type] = tp match { case tp: AppliedType => tp :: Nil - case tp: RefinedType if !config.Config.newScheme && tp.argInfos.nonEmpty => tp :: Nil // parameterized class type case tp: TypeRef if tp.symbol.isClass => tp :: Nil // monomorphic class type case tp: TypeProxy => stripToCore(tp.underlying) case AndType(tp1, tp2) => stripToCore(tp1) ::: stripToCore(tp2) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index df15baf77b62..83f7b6bbc046 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -213,16 +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 (firstParent, otherParents) = - if (config.Config.newScheme) { - val firstParent :: otherParents = cls.info.parentsNEW - (firstParent, otherParents) - } - else { - val firstParentRef :: otherParentRefs = cls.info.parentRefs // @!!! adapt - val firstParent = cls.appliedRef.baseTypeWithArgs(firstParentRef.symbol) - (firstParent, otherParentRefs) - } + val firstParent :: otherParents = cls.info.parentsNEW val superRef = if (cls is Trait) TypeTree(firstParent) else { @@ -269,9 +260,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)) - if (config.Config.newScheme) parents.head.parentsNEW.head :: parents - else parents.head.parentRefs.head :: parents + if (parents.head.classSymbol.is(Trait)) parents.head.parentsNEW.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/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index b48bbce23e58..4fcfb2155220 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -181,7 +181,4 @@ object Config { /** When in IDE, turn StaleSymbol errors into warnings instead of crashing */ final val ignoreStaleInIDE = true - - val newScheme = true - val newBoundsScheme = true } diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index bb061eaea749..28915f9c830c 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -338,9 +338,7 @@ object Contexts { * from constructor parameters to class parameter accessors. */ def superCallContext: Context = { - val locals = newScopeWith( - (if (Config.newScheme) owner.typeParams ++ owner.asClass.paramAccessors - else owner.asClass.paramAccessors): _*) + val locals = newScopeWith(owner.typeParams ++ owner.asClass.paramAccessors: _*) superOrThisCallContext(owner.primaryConstructor, locals) } diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 7f89006721fd..1041ca74cfe9 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -645,8 +645,7 @@ object Denotations { /** The TypeRef representing this type denotation at its original location. */ def appliedRef(implicit ctx: Context): Type = - if (Config.newScheme) typeRef.appliedTo(symbol.typeParams.map(_.typeRef)) - else typeRef + typeRef.appliedTo(symbol.typeParams.map(_.typeRef)) def typeRef(implicit ctx: Context): TypeRef = TypeRef(symbol.owner.thisType, symbol.name.asTypeName, this) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index e1a5aed2afcf..f256a8be4967 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -497,7 +497,7 @@ object Flags { /** The flags of a class type parameter */ final val ClassTypeParamCreationFlags = - TypeParam | Deferred | (if (config.Config.newScheme) Private else Protected) | Local + TypeParam | Deferred | Private | Local /** Flags that can apply to both a module val and a module class, except those that * are added at creation anyway @@ -593,7 +593,7 @@ object Flags { /** Is valid forever */ final val ValidForever = Package | Permanent | Scala2ExistentialCommon - /** A type parameter of a class or trait (works only under Config.newScheme) */ + /** A type parameter of a class or trait */ final val ClassTypeParam = allOf(TypeParam, Private) /** Is a default parameter in Scala 2*/ diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 940ec3c642aa..d81c06477da0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -402,54 +402,6 @@ class TypeApplications(val self: Type) extends AnyVal { } val stripped = self.stripTypeVar val dealiased = stripped.safeDealias - - /** Normalize a TypeBounds argument. This involves (1) propagating bounds - * from the type parameters into the argument, (2) possibly choosing the argument's - * upper or lower bound according to variance. - * - * Bounds propagation works as follows: If the dealiased type constructor is a TypeRef - * `p.c`, - * - take the type paramater bounds of `c` as seen from `p`, - * - substitute concrete (non-bound) arguments for corresponding formal type parameters, - * - interpolate, so that any (F-bounded) type parameters in the resulting bounds are avoided. - * The resulting bounds are joined (via &) with corresponding type bound arguments. - */ - def normalizeWildcardArg(typParams: List[TypeSymbol])(arg: Type, tparam: TypeSymbol): Type = arg match { - case TypeBounds(lo, hi) => - if (Config.newBoundsScheme) arg - else { - def avoidParams(seen: Set[Symbol], v: Int): ApproximatingTypeMap = new ApproximatingTypeMap { - variance = if (v >= 0) 1 else -1 - def apply(t: Type) = t match { - case t: TypeRef if typParams contains t.symbol => - val lo = atVariance(-variance)(apply(t.info.loBound)) - val hi = - if (seen.contains(t.symbol)) t.topType - else avoidParams(seen + t.symbol, variance)(t.info.hiBound) - range(lo, hi) - case _ => mapOver(t) - } - } - val v = tparam.paramVariance - val pbounds = dealiased match { - case dealiased @ TypeRef(prefix, _) => - val (concreteArgs, concreteParams) = // @!!! optimize? - args.zip(typParams).filter(!_._1.isInstanceOf[TypeBounds]).unzip - if (tparam.isCompleting) TypeBounds.empty - else avoidParams(Set(tparam), v)( - tparam.paramInfo.asSeenFrom(prefix, tparam.owner) - .subst(concreteParams, concreteArgs)) - case _ => - TypeBounds.empty - } - typr.println(i"normalize arg $arg for $tparam in $self app $args%, %, pbounds, = $pbounds") - if (v > 0) hi & pbounds.hiBound - else if (v < 0) lo | pbounds.loBound - else arg recoverable_& pbounds - } - case _ => arg - } - if (args.isEmpty || ctx.erasedTypes) self else dealiased match { case dealiased: HKTypeLambda => @@ -500,11 +452,7 @@ class TypeApplications(val self: Type) extends AnyVal { case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => HKApply(self, args) case dealiased => - if (Config.newScheme) { - val tparamSyms = typParams.asInstanceOf[List[TypeSymbol]] - AppliedType(self, args.zipWithConserve(tparamSyms)(normalizeWildcardArg(tparamSyms))) - } else - matchParams(dealiased, typParams, args) + AppliedType(self, args) } } @@ -540,48 +488,16 @@ class TypeApplications(val self: Type) extends AnyVal { /** The type arguments of this type's base type instance wrt. `base`. * Wildcard types in arguments are returned as TypeBounds instances. */ - final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = - if (Config.newScheme) - self.baseType(base).argInfos - else if (self derivesFrom base) - self.dealias match { - case self: TypeRef if !self.symbol.isClass => self.superType.baseArgInfos(base) - case self: HKApply => self.superType.baseArgInfos(base) - case _ => base.typeParams.map(param => self.member(param.name).info.argInfo) - } - else - Nil + final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = // @!!! drop + self.baseType(base).argInfos /** The base type including all type arguments and applicable refinements * of this type. Refinements are applicable if they refine a member of * the parent type which furthermore is not a name-mangled type parameter. * Existential types in arguments are returned as TypeBounds instances. */ - final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = - if (Config.newScheme) self.baseType(base) - else ctx.traceIndented(s"btwa ${self.show} wrt $base", core, show = true) { - def default = self.baseTypeTycon(base).appliedTo(baseArgInfos(base)) - def isExpandedTypeParam(sym: Symbol) = sym.is(TypeParam) && sym.name.is(ExpandedName) - self match { - case tp: TypeRef => - tp.info match { - case TypeBounds(_, hi) => hi.baseTypeWithArgs(base) - case _ => default - } - case tp @ RefinedType(parent, name, _) if !Config.newScheme && !isExpandedTypeParam(tp.member(name).symbol) => - tp.wrapIfMember(parent.baseTypeWithArgs(base)) - case tp: TermRef => - tp.underlying.baseTypeWithArgs(base) - case tp: HKApply => - tp.superType.baseTypeWithArgs(base) - case AndType(tp1, tp2) => - tp1.baseTypeWithArgs(base) & tp2.baseTypeWithArgs(base) - case OrType(tp1, tp2) => - tp1.baseTypeWithArgs(base) | tp2.baseTypeWithArgs(base) - case _ => - default - } - } + final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = // @!!! drop + self.baseType(base) /** Translate a type of the form From[T] to To[T], keep other types as they are. * `from` and `to` must be static classes, both with one type parameter, and the same variance. @@ -593,8 +509,7 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => if (self.derivesFrom(from)) if (ctx.erasedTypes) to.typeRef // @!!! can be dropped; appliedTo does the right thing anyway - else if (Config.newScheme) to.typeRef.appliedTo(self.baseType(from).argInfos) - else RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) + else to.typeRef.appliedTo(self.baseType(from).argInfos) else self } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 6a26a7880d92..b15623c2021b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1026,20 +1026,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val classBounds = tp2.classSymbols def recur(bcs: List[ClassSymbol]): Boolean = bcs match { case bc :: bcs1 => - if (Config.newScheme) - (classBounds.exists(bc.derivesFrom) && - variancesConform(bc.typeParams, tparams) && - p(tp1.baseType(bc)) - || - recur(bcs1)) - else { - val baseRef = tp1.baseTypeTycon(bc) - (classBounds.exists(bc.derivesFrom) && - variancesConform(baseRef.typeParams, tparams) && - p(baseRef.appliedTo(tp1.baseArgInfos(bc))) - || - recur(bcs1)) - } + (classBounds.exists(bc.derivesFrom) && + variancesConform(bc.typeParams, tparams) && + p(tp1.baseType(bc)) + || + recur(bcs1)) case nil => false } diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 4519eac55bda..f43fd3987909 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -258,56 +258,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. * all (possibly applied) references to classes. */ def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[Type] = { - if (Config.newScheme) return parents.mapConserve(_.dealias) // !@@@ track and eliminate usages? - // println(s"normalizing $parents of $cls in ${cls.owner}") // !!! DEBUG - - // A map consolidating all refinements arising from parent type parameters - var refinements: SimpleMap[TypeName, Type] = SimpleMap.Empty - - // A map of all formal type parameters of base classes that get refined - var formals: SimpleMap[TypeName, Symbol] = SimpleMap.Empty // A map of all formal parent parameter - - // Strip all refinements from parent type, populating `refinements` and `formals` maps. - def normalizeToRef(tp: Type): TypeRef = { - def fail = throw new TypeError(s"unexpected parent type: $tp") - tp.dealias match { - case tp: TypeRef => - tp - case tp @ RefinedType(tp1, name: TypeName, rinfo) => - val prevInfo = refinements(name) - refinements = refinements.updated(name, - if (prevInfo == null) tp.refinedInfo else prevInfo & tp.refinedInfo) - formals = formals.updated(name, tp1.typeParamNamed(name)) - normalizeToRef(tp1) - case tp @ RefinedType(tp1, _: TermName, _) => - normalizeToRef(tp1) - case _: ErrorType => - defn.AnyType - case AnnotatedType(tpe, _) => - normalizeToRef(tpe) - case HKApply(tycon: TypeRef, args) => - tycon.info match { - case TypeAlias(alias) => normalizeToRef(alias.appliedTo(args)) - case _ => fail - } - case _ => - fail - } - } - - val parentRefs = parents map normalizeToRef - - // Enter all refinements into current scope. - refinements foreachBinding { (name, refinedInfo) => - assert(decls.lookup(name) == NoSymbol, // DEBUG - s"redefinition of ${decls.lookup(name).debugString} in ${cls.showLocated}") - enterArgBinding(formals(name), refinedInfo, cls, decls) - } - - if (Config.forwardTypeParams) - forwardParamBindings(parentRefs, refinements, cls, decls) - - parentRefs + parents.mapConserve(_.dealias) // !@@@ track and eliminate usages? } /** Forward parameter bindings in baseclasses to argument types of diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9e5abe2145b3..1f311268c804 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1612,7 +1612,7 @@ object Types { } case _ => } - if (Config.checkTypeParamRefs && Config.newScheme) + if (Config.checkTypeParamRefs) lastDenotation match { case d: SingleDenotation if d.symbol.is(ClassTypeParam) => prefix match { @@ -1876,8 +1876,8 @@ object Types { } } - def isClassParam(implicit ctx: Context) = - Config.newScheme && symbol.is(TypeParam) && symbol.owner.isClass + def isClassParam(implicit ctx: Context) = // @!!! test flag combination instead? + symbol.is(TypeParam) && symbol.owner.isClass /** A selection of the same kind, but with potentially a different prefix. * The following normalizations are performed for type selections T#A: @@ -2313,7 +2313,7 @@ object Types { if (refinedName.isTermName) assert(refinedInfo.isInstanceOf[TermType]) else assert(refinedInfo.isInstanceOf[TypeType], this) - if (Config.newScheme) assert(!refinedName.is(NameKinds.ExpandedName), this) + assert(!refinedName.is(NameKinds.ExpandedName), this) override def underlying(implicit ctx: Context) = parent @@ -3123,7 +3123,7 @@ object Types { final val Provisional: DependencyStatus = 4 // set if dependency status can still change due to type variable instantiations } - // ----- HK types: LambdaParam, HKApply, TypeArgRef --------------------- + // ----- Type application: LambdaParam, AppliedType, TypeArgRef --------------------- /** The parameter of a type lambda */ case class LambdaParam(tl: TypeLambda, n: Int) extends ParamInfo { @@ -3308,15 +3308,13 @@ object Types { else arg recoverable_& rebase(pbounds) } - override def underlying(implicit ctx: Context): Type = - if (Config.newBoundsScheme) { - if (!ctx.hasSameBaseTypesAs(underlyingCachePeriod)) { - underlyingCache = computeUnderlying - underlyingCachePeriod = ctx.period - } - underlyingCache + override def underlying(implicit ctx: Context): Type = { + if (!ctx.hasSameBaseTypesAs(underlyingCachePeriod)) { + underlyingCache = computeUnderlying + underlyingCachePeriod = ctx.period } - else prefix.baseType(clsRef.symbol).argInfos.apply(idx) + underlyingCache + } def derivedTypeArgRef(prefix: Type)(implicit ctx: Context): Type = if (prefix eq this.prefix) this else TypeArgRef(prefix, clsRef, idx) @@ -3586,21 +3584,14 @@ object Types { private var selfTypeCache: Type = null - private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = - if (Config.newScheme) base.appliedTo(tparams.map(_.typeRef)) - else tparams match { - case tparam :: tparams1 => - fullyAppliedRef( - RefinedType(base, tparam.name, TypeRef(cls.thisType, tparam).toBounds(tparam)), - tparams1) - case nil => - base - } + //private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = + // base.appliedTo(tparams.map(_.typeRef)) /** The class type with all type parameters */ - def fullyAppliedRef(implicit ctx: Context): Type = - if (Config.newScheme && false) cls.appliedRef - else fullyAppliedRef(cls.typeRef, cls.typeParams) + def fullyAppliedRef(implicit ctx: Context): Type = // @!!! eliminate + //if (true) + cls.appliedRef + //else fullyAppliedRef(cls.typeRef, cls.typeParams) private var appliedRefCache: Type = null private var typeRefCache: TypeRef = null @@ -3621,8 +3612,7 @@ object Types { if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef else TypeRef(prefix, cls.name, clsDenot) appliedRefCache = - if (Config.newScheme) tref.appliedTo(cls.typeParams.map(_.typeRef)) - else tref + tref.appliedTo(cls.typeParams.map(_.typeRef)) // @!!! cache? } appliedRefCache } @@ -3634,19 +3624,10 @@ object Types { /** The parent type refs as seen from the given prefix */ override def parentRefs(implicit ctx: Context): List[TypeRef] = - if (Config.newScheme) parentsNEW.map(_.typeConstructor.asInstanceOf[TypeRef]) - else parentsNEW.mapconserve(_.asInstanceOf[TypeRef]) + parentsNEW.map(_.typeConstructor.asInstanceOf[TypeRef]) /** The parent types with all type arguments */ - override def parentsWithArgs(implicit ctx: Context): List[Type] = - if (Config.newScheme) parentsNEW - else 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) - else parent - } - } + override def parentsWithArgs(implicit ctx: Context): List[Type] = parentsNEW override def parentsNEW(implicit ctx: Context): List[Type] = { if (parentsCache == null) @@ -3774,6 +3755,7 @@ object Types { class RealTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) + // @!!! get rid of variance abstract class TypeAlias(val alias: Type, override val variance: Int) extends TypeBounds(alias, alias) { /** pre: this is a type alias */ def derivedTypeAlias(alias: Type, variance: Int = this.variance)(implicit ctx: Context) = diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index 91e6b2776c95..b0c5b722d281 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -328,19 +328,7 @@ class ClassfileParser( if (argsBuf != null) argsBuf += arg } accept('>') - if (skiptvs) tp - else if (config.Config.newScheme) tp.appliedTo(argsBuf.toList) - else { - var tp1: Type = tp - (argsBuf.toList, tp.typeParamSymbols).zipped.foreach { (arg, formal) => - val info = arg match { - case arg: TypeBounds => arg - case _ => TypeAlias(arg) - } - tp1 = RefinedType(tp1, formal.name, info) - } - tp1 - } + if (skiptvs) tp else tp.appliedTo(argsBuf.toList) } else tp case tp => assert(sig(index) != '<', tp) @@ -424,9 +412,8 @@ class ClassfileParser( val start = index while (sig(index) != '>') { val tpname = subName(':'.==).toTypeName - val expname = if (owner.isClass && !config.Config.newScheme) tpname.expandedName(owner) else tpname val s = ctx.newSymbol( - owner, expname, owner.typeParamCreationFlags, + owner, tpname, owner.typeParamCreationFlags, typeParamCompleter(index), coord = indexCoord(index)) if (owner.isClass) owner.asClass.enter(s) tparams = tparams + (tpname -> s) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 13d80732d4f4..3ff1d47caea9 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -485,10 +485,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case TYPEsym | ALIASsym => var name1 = name.asTypeName var flags1 = flags - if (flags is TypeParam) { - if (!dotty.tools.dotc.config.Config.newScheme) name1 = name1.expandedName(owner) - flags1 |= owner.typeParamCreationFlags - } + if (flags is TypeParam) flags1 |= owner.typeParamCreationFlags ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start) case CLASSsym => var infoRef = readNat() diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index fa4a707c7bdb..fac200b71fb9 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -563,7 +563,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { debug.println(i"refine($tp1, $tp2) = $res") res case (tp1 @ AppliedType(tycon, args), tp2: TypeRef) - if config.Config.newScheme && tp2.symbol.typeParams.nonEmpty && tp2.symbol.derivesFrom(tycon.typeSymbol) => + if tp2.symbol.typeParams.nonEmpty && tp2.symbol.derivesFrom(tycon.typeSymbol) => val tp1a = tp1.derivedAppliedType(refine(tycon, tp2), args) val res = derivingType(tp1a.asInstanceOf[AppliedType], tp2) debug.println(i"refine($tp1, $tp2) = $res") diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 218ec3f704a3..8b8d74a3324b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1146,10 +1146,8 @@ trait Applications extends Compatibility { self: Typer with Dynamic => else { val flip = new TypeMap { def apply(t: Type) = t match { - case t @ TypeAlias(alias) if variance > 0 && t.variance < 0 && !Config.newScheme => - t.derivedTypeAlias(defn.FunctionOf(alias :: Nil, defn.UnitType)) case t: TypeBounds => t - case t @ AppliedType(tycon, args) if Config.newScheme => + case t @ AppliedType(tycon, args) => def mapArg(arg: Type, tparam: TypeParamInfo) = if (variance > 0 && tparam.paramVariance < 0) defn.FunctionOf(arg :: Nil, defn.UnitType) else arg diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 844695582729..295e0a2a0c3d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -456,20 +456,12 @@ object Checking { tp.derivedClassInfo( prefix = apply(tp.prefix), classParentsNEW = - if (config.Config.newScheme) tp.parentsWithArgs.map { p => apply(p).stripAnnots match { case ref: RefType => ref case _ => defn.ObjectType // can happen if class files are missing } } - else - tp.parentsWithArgs.map { p => - apply(p).underlyingClassRef(refinementOK = false) match { - case ref: TypeRef => ref - case _ => defn.ObjectType // can happen if class files are missing - } - } ) case _ => mapOver(tp) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 18fc6c0a53c1..da7dd8b3e264 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -433,13 +433,7 @@ trait ImplicitRunInfo { self: RunInfo => comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } def addParentScope(parent: Type): Unit = - if (Config.newScheme) - iscopeRefs(tp.baseType(parent.typeSymbol)) foreach addRef - else { - iscopeRefs(parent.typeConstructor) foreach addRef - for (param <- parent.typeParamSymbols) - comps ++= iscopeRefs(tp.member(param.name).info) - } + iscopeRefs(tp.baseType(parent.typeSymbol)) foreach addRef val companion = cls.companionModule if (companion.exists) addRef(companion.valRef) cls.classParentsNEW foreach addParentScope From adde88e134aadfae8606846b0c6e04e8a1b9a877 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 16:39:19 +0200 Subject: [PATCH 074/146] Get rid of parentRefs and associated operations --- .../dotty/tools/dotc/core/Definitions.scala | 9 ++-- .../tools/dotc/core/SymDenotations.scala | 27 +++++------ .../src/dotty/tools/dotc/core/Symbols.scala | 3 +- .../src/dotty/tools/dotc/core/TypeOps.scala | 48 ------------------- .../src/dotty/tools/dotc/core/Types.scala | 35 +++++--------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +- .../core/unpickleScala2/Scala2Unpickler.scala | 7 +-- .../dotc/reporting/diagnostic/messages.scala | 2 +- .../tools/dotc/transform/CheckReentrant.scala | 2 +- .../dotc/transform/ExtensionMethods.scala | 2 +- .../tools/dotc/transform/PostTyper.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 7 ++- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- .../src/dotty/tools/dotc/typer/Typer.scala | 4 +- .../tools/dottydoc/model/factories.scala | 2 +- 18 files changed, 49 insertions(+), 115 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 9a8f94e4eff4..5b4f04312208 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -80,10 +80,9 @@ class Definitions { val typeParam = enterSyntheticTypeParam(cls, paramFlags, paramDecls) def instantiate(tpe: Type) = if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef) - else tpe - val parents = parentConstrs.toList map instantiate - val parentRefs = ctx.normalizeToClassRefs(parents, cls, paramDecls) - denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls) + else tpe.dealias + val parents = parentConstrs.toList + denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parents, paramDecls) } } newClassSymbol(ScalaPackageClass, name, EmptyFlags, completer).entered @@ -123,7 +122,7 @@ class Definitions { if (name.firstPart.startsWith(str.ImplicitFunction)) { val superTrait = FunctionType(arity).appliedTo(argParams.map(_.typeRef) ::: resParam.typeRef :: Nil) - (ImplicitMethodType, ctx.normalizeToClassRefs(superTrait :: Nil, cls, decls)) + (ImplicitMethodType, superTrait :: Nil) } else (MethodType, Nil) val applyMeth = diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index edd28cbd006a..0227ecb91d19 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1223,7 +1223,7 @@ object SymDenotations { info2 match { case info2: ClassInfo => info1 match { - case info1: ClassInfo => info1.classParentsNEW ne info2.classParentsNEW + case info1: ClassInfo => info1.classParents ne info2.classParents case _ => completersMatter } case _ => completersMatter @@ -1366,25 +1366,19 @@ object SymDenotations { super.info_=(tp) } - /** The denotations of all parents in this class. */ - def classParentRefs(implicit ctx: Context): List[TypeRef] = info match { - case classInfo: ClassInfo => classInfo.parentRefs - case _ => Nil - } - - /** The denotations of all parents in this class. */ + /** The denotations of all parents in this class. */ def classParentsWithArgs(implicit ctx: Context): List[Type] = info match { case classInfo: ClassInfo => classInfo.parentsWithArgs case _ => Nil } - def classParentsNEW(implicit ctx: Context): List[Type] = info match { + def classParents(implicit ctx: Context): List[Type] = info match { case classInfo: ClassInfo => classInfo.parentsNEW case _ => Nil } /** The symbol of the superclass, NoSymbol if no superclass exists */ - def superClass(implicit ctx: Context): Symbol = classParentsNEW match { + def superClass(implicit ctx: Context): Symbol = classParents match { case parent :: _ => val cls = parent.classSymbol if (cls is Trait) NoSymbol else cls @@ -1457,10 +1451,13 @@ object SymDenotations { def computeBaseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = { def emptyParentsExpected = is(Package) || (symbol == defn.AnyClass) || ctx.erasedTypes && (symbol == defn.ObjectClass) - if (classParentsNEW.isEmpty && !emptyParentsExpected) + if (classParents.isEmpty && !emptyParentsExpected) onBehalf.signalProvisional() val builder = new BaseDataBuilder - for (p <- classParentsNEW) builder.addAll(p.typeSymbol.asClass.baseClasses) + for (p <- classParents) { + assert(p.typeSymbol.isClass, s"$this has $p") + builder.addAll(p.typeSymbol.asClass.baseClasses) + } (classSymbol :: builder.baseClasses, builder.baseClassSet) } @@ -1601,7 +1598,7 @@ object SymDenotations { denots } if (name.isConstructorName) ownDenots - else collect(ownDenots, classParentsNEW) + else collect(ownDenots, classParents) } override final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = { @@ -1659,7 +1656,7 @@ object SymDenotations { case _ => false } if (isOwnThis) - if (clsd.baseClassSet.contains(symbol)) foldGlb(NoType, clsd.classParentsNEW) + if (clsd.baseClassSet.contains(symbol)) foldGlb(NoType, clsd.classParents) else NoType else baseTypeOf(clsd.typeRef).asSeenFrom(prefix, owner) @@ -1737,7 +1734,7 @@ object SymDenotations { def computeMemberNames(keepOnly: NameFilter)(implicit onBehalf: MemberNames, ctx: Context): Set[Name] = { var names = Set[Name]() def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name - for (p <- classParentsNEW) + for (p <- classParents) for (name <- p.typeSymbol.asClass.memberNames(keepOnly)) maybeAdd(name) val ownSyms = diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index d9577f05e842..bb3ff7dae021 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -123,8 +123,7 @@ trait Symbols { this: Context => def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val cls = denot.asClass.classSymbol val decls = newScope - val parentRefs = normalizeToClassRefs(parentTypes, cls, decls) - denot.info = ClassInfo(owner.thisType, cls, parentRefs, decls) + denot.info = ClassInfo(owner.thisType, cls, parentTypes.map(_.dealias), decls) } } newClassSymbol(owner, name, flags, completer, privateWithin, coord, assocFile) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index f43fd3987909..6fdf2d060cf4 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -261,54 +261,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. parents.mapConserve(_.dealias) // !@@@ track and eliminate usages? } - /** Forward parameter bindings in baseclasses to argument types of - * class `cls` if possible. - * If there have member definitions - * - * type param v= middle - * type middle v= to - * - * where the variances of both alias are the same, then enter a new definition - * - * type param v= to - * - * If multiple forwarders would be generated, join their `to` types with an `&`. - * - * @param cls The class for which parameter bindings should be forwarded - * @param decls Its scope - * @param parentRefs The parent type references of `cls` - * @param paramBindings The type parameter bindings generated for `cls` - * - */ - def forwardParamBindings(parentRefs: List[TypeRef], - paramBindings: SimpleMap[TypeName, Type], - cls: ClassSymbol, decls: Scope)(implicit ctx: Context) = { - - def forwardRef(argSym: Symbol, from: TypeName, to: TypeAlias) = argSym.info match { - case info @ TypeAlias(TypeRef(_: ThisType, `from`)) if info.variance == to.variance => - val existing = decls.lookup(argSym.name) - if (existing.exists) existing.info = existing.info & to - else enterArgBinding(argSym, to, cls, decls) - case _ => - } - - def forwardRefs(from: TypeName, to: Type) = to match { - case to: TypeAlias => - for (pref <- parentRefs) { - def forward()(implicit ctx: Context): Unit = - for (argSym <- pref.decls) - if (argSym is BaseTypeArg) forwardRef(argSym, from, to) - pref.info match { - case info: TempClassInfo => info.addSuspension(implicit ctx => forward()) - case _ => forward() - } - } - case _ => - } - - paramBindings.foreachBinding(forwardRefs) - } - /** An argument bounds violation is a triple consisting of * - the argument tree * - a string "upper" or "lower" indicating which bound is violated diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1f311268c804..f5917663e8bf 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1193,15 +1193,6 @@ object Types { NoType } - /** For a ClassInfo type, its parents, - * Inherited by all type proxies. Empty for all other types. - * Overwritten in ClassInfo, where parents is cached. - */ - 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 @@ -1224,8 +1215,8 @@ object Types { } /** The first parent of this type, AnyRef if list of parents is empty */ - def firstParentRef(implicit ctx: Context): TypeRef = parentRefs match { - case p :: _ => p + def firstParentRef(implicit ctx: Context): TypeRef = parentsNEW match { // @!!! needed? + case p :: _ => p.typeConstructor.asInstanceOf[TypeRef] case _ => defn.AnyType } @@ -3559,7 +3550,7 @@ object Types { abstract case class ClassInfo( prefix: Type, cls: ClassSymbol, - classParentsNEW: List[Type], + classParents: List[Type], decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { @@ -3622,30 +3613,26 @@ object Types { // cached because baseType needs parents private var parentsCache: List[Type] = null - /** The parent type refs as seen from the given prefix */ - override def parentRefs(implicit ctx: Context): List[TypeRef] = - parentsNEW.map(_.typeConstructor.asInstanceOf[TypeRef]) - /** The parent types with all type arguments */ override def parentsWithArgs(implicit ctx: Context): List[Type] = parentsNEW override def parentsNEW(implicit ctx: Context): List[Type] = { if (parentsCache == null) - parentsCache = classParentsNEW.mapConserve(_.asSeenFrom(prefix, cls.owner)) + parentsCache = classParents.mapConserve(_.asSeenFrom(prefix, cls.owner)) parentsCache } def derivedClassInfo(prefix: Type)(implicit ctx: Context) = if (prefix eq this.prefix) this - else ClassInfo(prefix, cls, classParentsNEW, decls, selfInfo) + else ClassInfo(prefix, cls, classParents, decls, selfInfo) - def derivedClassInfo(prefix: Type = this.prefix, classParentsNEW: List[Type] = this.classParentsNEW, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = - if ((prefix eq this.prefix) && (classParentsNEW eq this.classParentsNEW) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this - else ClassInfo(prefix, cls, classParentsNEW, decls, selfInfo) + def derivedClassInfo(prefix: Type = this.prefix, classParents: List[Type] = this.classParents, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) = + if ((prefix eq this.prefix) && (classParents eq this.classParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this + else ClassInfo(prefix, cls, classParents, decls, selfInfo) override def computeHash = doHash(cls, prefix) - override def toString = s"ClassInfo($prefix, $cls, $classParentsNEW)" + override def toString = s"ClassInfo($prefix, $cls, $classParents)" } class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: DotClass) @@ -3663,9 +3650,9 @@ object Types { def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension - /** Install classinfo with known parents in `denot` and resume all suspensions */ + /** Install classinfo with known parents in `denot` and resume all suspensions */ // @!!! elim def finalize(denot: SymDenotation, parents: List[Type])(implicit ctx: Context) = { - denot.info = derivedClassInfo(classParentsNEW = parents) + denot.info = derivedClassInfo(classParents = parents) suspensions.foreach(_(ctx)) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index b2d494add104..f287edc4e821 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -731,14 +731,14 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi case _ => readTpt() } } - val parentRefs = ctx.normalizeToClassRefs(parents.map(_.tpe), cls, cls.unforcedDecls) + val parentTypes = parents.map(_.tpe.dealias) val self = if (nextByte == SELFDEF) { readByte() untpd.ValDef(readName(), readTpt(), EmptyTree).withType(NoType) } else EmptyValDef - cls.info = ClassInfo(cls.owner.thisType, cls, parentRefs, cls.unforcedDecls, + cls.info = ClassInfo(cls.owner.thisType, cls, parentTypes, cls.unforcedDecls, if (self.isEmpty) NoType else self.tpt.tpe) cls.setNoInitsFlags(fork.indexStats(end)) val constr = readIndexedDef().asInstanceOf[DefDef] diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 3ff1d47caea9..64b0587f44ef 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -99,8 +99,9 @@ object Scala2Unpickler { else selfInfo val tempInfo = new TempClassInfo(denot.owner.thisType, denot.classSymbol, decls, ost) denot.info = tempInfo // first rough info to avoid CyclicReferences - var parentRefs = ctx.normalizeToClassRefs(parents, cls, decls) - if (parentRefs.isEmpty) parentRefs = defn.ObjectType :: Nil + val normalizedParents = + if (parents.isEmpty) defn.ObjectType :: Nil + else parents.map(_.dealias) for (tparam <- tparams) { val tsym = decls.lookup(tparam.name) if (tsym.exists) tsym.setFlag(TypeParam) @@ -124,7 +125,7 @@ object Scala2Unpickler { registerCompanionPair(scalacCompanion, denot.classSymbol) } - tempInfo.finalize(denot, parentRefs) // install final info, except possibly for typeparams ordering + tempInfo.finalize(denot, normalizedParents) // install final info, except possibly for typeparams ordering denot.ensureTypeParamsInCorrectOrder() } } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 64717e980e61..60ccc51190d8 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1284,7 +1284,7 @@ object messages { val msg = hl"""|$qual does not name a parent of $cls""" val kind = "Reference" - private val parents: Seq[String] = (cls.info.parentRefs map (_.name.show)).sorted + private val parents: Seq[String] = (cls.info.parentsNEW map (_.typeSymbol.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/CheckReentrant.scala b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala index 94c186a2ac19..878b3af95f12 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala @@ -81,7 +81,7 @@ class CheckReentrant extends MiniPhaseTransform { thisTransformer => sym.info.widenExpr.classSymbols.foreach(addVars) } } - for (parent <- cls.classInfo.classParentsNEW) + for (parent <- cls.classInfo.classParents) addVars(parent.typeSymbol.asClass) } } diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 02cf547b72e5..f05afe82da48 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -102,7 +102,7 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful moduleClassSym.copySymDenotation(info = cinfo.derivedClassInfo( // FIXME: use of VC*Companion superclasses is disabled until the conflicts with SyntheticMethods are solved. - //classParents = ctx.normalizeToClassRefs(List(newSuperClass), moduleSym, decls1), + //classParents = List(newSuperClass) decls = decls1)) case _ => moduleClassSym diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 049b96c561a0..f620191c5d92 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -251,7 +251,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran // Add Child annotation to sealed parents unless current class is anonymous if (!sym.isAnonymousClass) // ignore anonymous class - sym.asClass.classParentsNEW.foreach { parent => + sym.asClass.classParents.foreach { parent => val sym2 = if (sym.is(Module)) sym.sourceModule else sym registerChild(sym2, parent) } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 295e0a2a0c3d..461668548328 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -455,7 +455,7 @@ object Checking { case tp: ClassInfo => tp.derivedClassInfo( prefix = apply(tp.prefix), - classParentsNEW = + classParents = tp.parentsWithArgs.map { p => apply(p).stripAnnots match { case ref: RefType => ref diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index da7dd8b3e264..06b933c21d6e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -436,7 +436,7 @@ trait ImplicitRunInfo { self: RunInfo => iscopeRefs(tp.baseType(parent.typeSymbol)) foreach addRef val companion = cls.companionModule if (companion.exists) addRef(companion.valRef) - cls.classParentsNEW foreach addParentScope + cls.classParents foreach addParentScope } tp.classSymbols(liftingCtx) foreach addClassScope case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 836133883789..384b57b85198 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -860,7 +860,7 @@ class Namer { typer: Typer => * (4) If the class is sealed, it is defined in the same compilation unit as the current class */ def checkedParentType(parent: untpd.Tree): Type = { - val ptype = parentType(parent)(ctx.superCallContext) + val ptype = parentType(parent)(ctx.superCallContext).dealias if (cls.isRefinementClass) ptype else { val pt = checkClassType(ptype, parent.pos, @@ -914,10 +914,9 @@ class Namer { typer: Typer => symbolOfTree(constr).ensureCompleted() val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)), cls.pos) - val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls) - typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %, parentRefs = $parentRefs%, %") + typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %") - tempInfo.finalize(denot, parentRefs) + tempInfo.finalize(denot, parentTypes) Checking.checkWellFormed(cls) if (isDerivedValueClass(cls)) cls.setFlag(Final) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 4d3ba7f02889..f5dca02e836b 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -102,7 +102,7 @@ object RefChecks { ctx.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), cls.pos) } - for (parent <- cinfo.classParentsNEW) + for (parent <- cinfo.classParents) checkSelfConforms(parent.typeSymbol.asClass, "illegal inheritance", "parent") for (reqd <- cinfo.cls.givenSelfType.classSymbols) checkSelfConforms(reqd, "missing requirement", "required") diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 1f25a9d186d3..82a2a3fa1dfe 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -308,9 +308,9 @@ 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.parentRefs filter (_.name == mix.name) match { + def findMixinSuper(site: Type): Type = site.parentsNEW filter (_.typeSymbol.name == mix.name) match { case p :: Nil => - p + p.typeConstructor case Nil => errorType(SuperQualMustBeParent(mix, cls), tree.pos) case p :: q :: _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index cd50fb743361..f23ca38d352b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1422,7 +1422,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } // Check that phantom lattices are defined in a static object - if (cls.classParentsNEW.exists(_.typeSymbol eq defn.PhantomClass) && !cls.isStaticOwner) + if (cls.classParents.exists(_.typeSymbol eq defn.PhantomClass) && !cls.isStaticOwner) ctx.error("only static objects can extend scala.Phantom", cdef.pos) // check value class constraints @@ -1455,7 +1455,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def realClassParent(cls: Symbol): ClassSymbol = if (!cls.isClass) defn.ObjectClass else if (!(cls is Trait)) cls.asClass - else cls.asClass.classParentsNEW match { + else cls.asClass.classParents match { case parentRef :: _ => realClassParent(parentRef.typeSymbol) case nil => defn.ObjectClass } diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 2e14b83bceb1..e045bf84a4ca 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -198,7 +198,7 @@ object factories { case _ => false } - cd.classParentRefs.collect { + cd.classParents.map(_.typeConstructor).collect { case t: TypeRef if !isJavaLangObject(t) && !isProductWithArity(t) => UnsetLink(t.name.toString, path(t.symbol).mkString(".")) } From 0b4c35c56ae91101d92c578d842e80b23c08ef4a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 17:07:57 +0200 Subject: [PATCH 075/146] Re-normalize parents methods - get rid of withArgs variants - drop the NEW --- .../backend/jvm/DottyBackendInterface.scala | 2 +- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +-- .../src/dotty/tools/dotc/config/Config.scala | 7 ----- .../tools/dotc/core/SymDenotations.scala | 8 +---- .../tools/dotc/core/TypeApplications.scala | 8 ----- .../src/dotty/tools/dotc/core/TypeOps.scala | 15 ++------- .../src/dotty/tools/dotc/core/Types.scala | 31 +++++-------------- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 6 ++-- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../dotc/reporting/diagnostic/messages.scala | 2 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- .../tools/dotc/transform/CrossCastAnd.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotc/transform/FullParameterization.scala | 2 +- .../dotc/transform/OverridingPairs.scala | 2 +- .../dotc/transform/PatternMatcherOld.scala | 2 +- .../dotty/tools/dotc/transform/TailRec.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 8 ++--- .../src/dotty/tools/dotc/typer/Typer.scala | 5 ++- 24 files changed, 37 insertions(+), 85 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 7831260e1bc5..40b8412308a4 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -897,7 +897,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma // to inner symbols of DefDef // todo: somehow handle. - def parents: List[Type] = tp.parentsNEW + def parents: List[Type] = tp.parents } object Assign extends AssignDeconstructor { diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 83f7b6bbc046..c8cb259a243e 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 firstParent :: otherParents = cls.info.parentsNEW + val firstParent :: otherParents = cls.info.parents val superRef = if (cls is Trait) TypeTree(firstParent) else { @@ -260,7 +260,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.parentsNEW.head :: parents + if (parents.head.classSymbol.is(Trait)) parents.head.parents.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/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index 4fcfb2155220..fe4de40ec038 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -84,13 +84,6 @@ object Config { /** If this flag is set, take the fast path when comparing same-named type-aliases and types */ final val fastPathForRefinedSubtype = true - /** If this flag is set, `TypeOps.normalizeToClassRefs` will insert forwarders - * for type parameters of base classes. This is an optimization, which avoids - * long alias chains. We should not rely on the optimization, though. So changing - * the flag to false can be used for checking that everything works OK without it. - */ - final val forwardTypeParams = true - /** If this flag is set, and we compute `T1 { X = S1 }` & `T2 { X = S2 }` as a new * upper bound of a constrained parameter, try to align the refinements by computing * `S1 =:= S2` (which might instantiate type parameters). diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 0227ecb91d19..e5bf2c197d07 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1366,14 +1366,8 @@ object SymDenotations { super.info_=(tp) } - /** The denotations of all parents in this class. */ - def classParentsWithArgs(implicit ctx: Context): List[Type] = info match { - case classInfo: ClassInfo => classInfo.parentsWithArgs - case _ => Nil - } - def classParents(implicit ctx: Context): List[Type] = info match { - case classInfo: ClassInfo => classInfo.parentsNEW + case classInfo: ClassInfo => classInfo.parents case _ => Nil } diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index d81c06477da0..68c42aa5dc51 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -491,14 +491,6 @@ class TypeApplications(val self: Type) extends AnyVal { final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = // @!!! drop self.baseType(base).argInfos - /** The base type including all type arguments and applicable refinements - * of this type. Refinements are applicable if they refine a member of - * the parent type which furthermore is not a name-mangled type parameter. - * Existential types in arguments are returned as TypeBounds instances. - */ - final def baseTypeWithArgs(base: Symbol)(implicit ctx: Context): Type = // @!!! drop - self.baseType(base) - /** Translate a type of the form From[T] to To[T], keep other types as they are. * `from` and `to` must be static classes, both with one type parameter, and the same variance. * Do the same for by name types => From[T] and => To[T] diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 6fdf2d060cf4..eec1d093d4a7 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -198,12 +198,8 @@ trait TypeOps { this: Context => // TODO: Make standalone object. case _ => val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect) val doms = dominators(commonBaseClasses, Nil) - def baseTp(cls: ClassSymbol): Type = { - val base = - if (tp1.typeParams.nonEmpty) tp.baseTypeTycon(cls) - else tp.baseTypeWithArgs(cls) - base.mapReduceOr(identity)(mergeRefinedOrApplied) - } + def baseTp(cls: ClassSymbol): Type = + tp.baseType(cls).mapReduceOr(identity)(mergeRefinedOrApplied) doms.map(baseTp).reduceLeft(AndType.apply) } } @@ -254,13 +250,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. cls.enter(sym, decls) } - /** Normalize a list of parent types of class `cls` to make sure they are - * all (possibly applied) references to classes. - */ - def normalizeToClassRefs(parents: List[Type], cls: ClassSymbol, decls: Scope): List[Type] = { - parents.mapConserve(_.dealias) // !@@@ track and eliminate usages? - } - /** An argument bounds violation is a triple consisting of * - the argument tree * - a string "upper" or "lower" indicating which bound is violated diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f5917663e8bf..bc311ef41f1c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -856,7 +856,7 @@ object Types { } /** Temporary replacement for baseTypeRef */ - final def baseTypeTycon(base: Symbol)(implicit ctx: Context): Type = + final def baseTypeTycon(base: Symbol)(implicit ctx: Context): Type = // @!!! drop baseType(base).typeConstructor def & (that: Type)(implicit ctx: Context): Type = track("&") { @@ -1194,34 +1194,22 @@ object Types { } /** The full parent types, including all type arguments */ - def parentsWithArgs(implicit ctx: Context): List[Type] = this match { - case tp: TypeProxy => tp.superType.parentsWithArgs - case _ => Nil - } - - /** The full parent types, including (in new scheme) all type arguments */ - def parentsNEW(implicit ctx: Context): List[Type] = this match { + def parents(implicit ctx: Context): List[Type] = this match { case tp @ AppliedType(tycon, args) if tycon.typeSymbol.isClass => - tycon.parentsNEW.map(_.subst(tycon.typeSymbol.typeParams, args)) + tycon.parents.map(_.subst(tycon.typeSymbol.typeParams, args)) // !@@@ cache? case tp: TypeRef => if (tp.info.isInstanceOf[TempClassInfo]) { tp.reloadDenot() assert(!tp.info.isInstanceOf[TempClassInfo]) } - tp.info.parentsNEW + tp.info.parents case tp: TypeProxy => - tp.superType.parentsNEW + tp.superType.parents case _ => Nil } /** The first parent of this type, AnyRef if list of parents is empty */ - def firstParentRef(implicit ctx: Context): TypeRef = parentsNEW match { // @!!! needed? - case p :: _ => p.typeConstructor.asInstanceOf[TypeRef] - case _ => defn.AnyType - } - - /** The first parent of this type, AnyRef if list of parents is empty */ - def firstParentNEW(implicit ctx: Context): Type = parentsNEW match { + def firstParent(implicit ctx: Context): Type = parents match { case p :: _ => p case _ => defn.AnyType } @@ -3613,10 +3601,7 @@ object Types { // cached because baseType needs parents private var parentsCache: List[Type] = null - /** The parent types with all type arguments */ - override def parentsWithArgs(implicit ctx: Context): List[Type] = parentsNEW - - override def parentsNEW(implicit ctx: Context): List[Type] = { + override def parents(implicit ctx: Context): List[Type] = { if (parentsCache == null) parentsCache = classParents.mapConserve(_.asSeenFrom(prefix, cls.owner)) parentsCache @@ -4136,7 +4121,7 @@ object Types { abstract class DeepTypeMap(implicit ctx: Context) extends TypeMap { override def mapClassInfo(tp: ClassInfo) = { val prefix1 = this(tp.prefix) - val parents1 = tp.parentsNEW mapConserve this + val parents1 = tp.parents mapConserve this val selfInfo1 = tp.selfInfo match { case selfInfo: Type => this(selfInfo) case selfInfo => selfInfo diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 64b0587f44ef..6a5236a7d25a 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -733,7 +733,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas if (sym.owner != thispre.cls) { val overriding = thispre.cls.info.decls.lookup(sym.name) if (overriding.exists && overriding != sym) { - val base = pre.baseTypeWithArgs(sym.owner) + val base = pre.baseType(sym.owner) assert(base.exists) pre = SuperType(thispre, base) } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 623cbdc07c28..d61b49536ee7 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -322,7 +322,7 @@ class PlainPrinter(_ctx: Context) extends Printer { if (tp.variance == 1) " =+ " else if (tp.variance == -1) " =- " else " = " - eql ~ toText(tp.alias) + eql ~ toText(tp.alias) case tp @ TypeBounds(lo, hi) => (if (lo isRef defn.NothingClass) Text() else " >: " ~ toText(lo)) ~ (if (hi isRef defn.AnyClass) Text() else " <: " ~ toText(hi)) @@ -340,7 +340,7 @@ class PlainPrinter(_ctx: Context) extends Printer { val declsText = if (trueDecls.isEmpty || !ctx.settings.debug.value) Text() else dclsText(trueDecls) - tparamsText ~ " extends " ~ toTextParents(tp.parentsNEW) ~ "{" ~ selfText ~ declsText ~ + tparamsText ~ " extends " ~ toTextParents(tp.parents) ~ "{" ~ selfText ~ declsText ~ "} at " ~ preText case tp => ": " ~ toTextGlobal(tp) @@ -418,7 +418,7 @@ class PlainPrinter(_ctx: Context) extends Printer { def toText(sym: Symbol): Text = (kindString(sym) ~~ { - if (sym.isAnonymousClass) toText(sym.info.parentsNEW, " with ") ~ "{...}" + if (sym.isAnonymousClass) toText(sym.info.parents, " with ") ~ "{...}" else if (hasMeaninglessName(sym)) simpleNameString(sym.owner) + idString(sym) else nameString(sym) }).close diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index a8b9ca2979f1..6e880d19d0b4 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -164,7 +164,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case ErasedValueType(tycon, underlying) => return "ErasedValueType(" ~ toText(tycon) ~ ", " ~ toText(underlying) ~ ")" case tp: ClassInfo => - return toTextParents(tp.parentsWithArgs) ~ "{...}" + return toTextParents(tp.parents) ~ "{...}" case JavaArrayType(elemtp) => return toText(elemtp) ~ "[]" case tp: AnnotatedType if homogenizedView => diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 60ccc51190d8..301c9d1582d2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1284,7 +1284,7 @@ object messages { val msg = hl"""|$qual does not name a parent of $cls""" val kind = "Reference" - private val parents: Seq[String] = (cls.info.parentsNEW map (_.typeSymbol.name.show)).sorted + private val parents: Seq[String] = (cls.info.parents map (_.typeSymbol.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/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index b34eade299ee..c0eea50822b6 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -236,7 +236,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder def linearizedAncestorTypes(info: ClassInfo): List[Type] = { val ref = info.fullyAppliedRef // Note that the ordering of classes in `baseClasses` is important. - info.baseClasses.tail.map(ref.baseTypeWithArgs) + info.baseClasses.tail.map(ref.baseType) } def apiDefinitions(defs: List[Symbol]): List[api.Definition] = { diff --git a/compiler/src/dotty/tools/dotc/transform/CrossCastAnd.scala b/compiler/src/dotty/tools/dotc/transform/CrossCastAnd.scala index 4fc4ef10b65c..838286e81181 100644 --- a/compiler/src/dotty/tools/dotc/transform/CrossCastAnd.scala +++ b/compiler/src/dotty/tools/dotc/transform/CrossCastAnd.scala @@ -24,7 +24,7 @@ class CrossCastAnd extends MiniPhaseTransform { thisTransform => lazy val qtype = tree.qualifier.tpe.widen val sym = tree.symbol if (sym.is(Flags.Private) && qtype.typeSymbol != sym.owner) - cpy.Select(tree)(tree.qualifier.asInstance(AndType(qtype.baseTypeWithArgs(sym.owner), tree.qualifier.tpe)), tree.name) + cpy.Select(tree)(tree.qualifier.asInstance(AndType(qtype.baseType(sym.owner), tree.qualifier.tpe)), tree.name) else tree } } diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index f32d0b8a591a..4d2a6c454644 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -409,7 +409,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.firstParentRef)) + qual.withType(SuperType(thisType, thisType.firstParent.typeConstructor)) case _ => qual } diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 284a8b3649f5..83491c19efef 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -213,7 +213,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.info.parentsNEW.exists(parent => // needs outer to potentially pass along to parent + cls.info.parents.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/FullParameterization.scala b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala index f3669c845a74..fbf48e6a15de 100644 --- a/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala +++ b/compiler/src/dotty/tools/dotc/transform/FullParameterization.scala @@ -163,7 +163,7 @@ trait FullParameterization { def rewireCall(thisArg: Tree): Tree = { val rewired = rewiredTarget(tree, derived) if (rewired.exists) { - val base = thisArg.tpe.baseTypeWithArgs(origClass) + val base = thisArg.tpe.baseType(origClass) assert(base.exists) ref(rewired.termRef) .appliedToTypeTrees(targs ++ base.argInfos.map(TypeTree(_))) diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index 44c17d15178c..cbd79d5c50d6 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.parentsNEW.toArray map (_.typeSymbol) + protected def parents: Array[Symbol] = base.info.parents.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/transform/PatternMatcherOld.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala index 55d0d7a0c034..4f196280c2de 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala @@ -1359,7 +1359,7 @@ class PatternMatcherOld extends MiniPhaseTransform with DenotTransformer { // don't go looking for selectors if we only expect one pattern def rawSubPatTypes = aligner.extractedTypes - def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp.baseTypeWithArgs(baseClass)).argInfos match { + def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp.baseType(baseClass)).argInfos match { case x :: Nil => x case _ => or } diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 906a9d5c3ad7..a99a41921abd 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -254,7 +254,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete val callTargs: List[tpd.Tree] = if (abstractOverClass) { - val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos + val classTypeArgs = recv.tpe.baseType(enclosingClass).argInfos targs ::: classTypeArgs.map(x => ref(x.typeSymbol)) } else targs diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 8b8d74a3324b..acbb1298d542 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -915,7 +915,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.firstParentNEW) + case tp: TypeRef if tp.symbol.isClass => isSubTypeOfParent(subtp, tp.firstParent) case tp: TypeProxy => isSubTypeOfParent(subtp, tp.superType) case _ => false } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 461668548328..df3c85259174 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -456,7 +456,7 @@ object Checking { tp.derivedClassInfo( prefix = apply(tp.prefix), classParents = - tp.parentsWithArgs.map { p => + tp.parents.map { p => apply(p).stripAnnots match { case ref: RefType => ref case _ => defn.ObjectType // can happen if class files are missing diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index f5dca02e836b..c3a36ac283ca 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -287,7 +287,7 @@ object RefChecks { //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG return } - val parentSymbols = clazz.info.parentsNEW.map(_.typeSymbol) + val parentSymbols = clazz.info.parents.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 82a2a3fa1dfe..b5c3e3fb5556 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -47,7 +47,7 @@ trait TypeAssigner { */ def classBound(info: ClassInfo)(implicit ctx: Context): Type = { val cls = info.cls - val parentType = info.parentsWithArgs.reduceLeft(ctx.typeComparer.andType(_, _)) + val parentType = info.parents.reduceLeft(ctx.typeComparer.andType(_, _)) def addRefinement(parent: Type, decl: Symbol) = { val inherited = @@ -308,7 +308,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.parentsNEW filter (_.typeSymbol.name == mix.name) match { + def findMixinSuper(site: Type): Type = site.parents filter (_.typeSymbol.name == mix.name) match { case p :: Nil => p.typeConstructor case Nil => @@ -319,9 +319,9 @@ trait TypeAssigner { val owntype = if (mixinClass.exists) mixinClass.appliedRef else if (!mix.isEmpty) findMixinSuper(cls.info) - else if (inConstrCall || ctx.erasedTypes) cls.info.firstParentRef + else if (inConstrCall || ctx.erasedTypes) cls.info.firstParent.typeConstructor else { - val ps = cls.classInfo.parentsWithArgs + val ps = cls.classInfo.parents if (ps.isEmpty) defn.AnyType else ps.reduceLeft((x: Type, y: Type) => x & y) } tree.withType(SuperType(cls.thisType, owntype)) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f23ca38d352b..d0cb1d8d896a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1467,9 +1467,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case p :: _ if p.classSymbol.isRealClass => parents case _ => val pcls = (defn.ObjectClass /: parents)(improve) - typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %") - val first = ctx.typeComparer.glb( - defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls))) + typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseType pcls)}%, %") + val first = ctx.typeComparer.glb(defn.ObjectType :: parents.map(_.baseType(pcls))) checkFeasibleParent(first, pos, em" in inferred superclass $first") :: parents } } From f65162bcb788f28af50a9f19cfad64bb12e1bd10 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 17:27:57 +0200 Subject: [PATCH 076/146] Fix rebase breakage, drop old UserfacingPrinter --- .../dotty/tools/repl/UserFacingPrinter.scala | 158 ------------------ 1 file changed, 158 deletions(-) delete mode 100644 repl/src/dotty/tools/repl/UserFacingPrinter.scala diff --git a/repl/src/dotty/tools/repl/UserFacingPrinter.scala b/repl/src/dotty/tools/repl/UserFacingPrinter.scala deleted file mode 100644 index 909c0225085b..000000000000 --- a/repl/src/dotty/tools/repl/UserFacingPrinter.scala +++ /dev/null @@ -1,158 +0,0 @@ -package dotty.tools -package repl - -import dotc.ast.Trees.{ Untyped, Tree } -import dotc.core.Annotations.Annotation -import dotc.core.Constants.Constant -import dotc.core.Contexts.Context -import dotc.core.Denotations.{ Denotation, MultiDenotation, SingleDenotation } -import dotc.core.Flags._ -import dotc.core.TypeApplications.{ AnyAppliedType, EtaExpansion } -import dotc.core.Names._ -import dotc.core.NameOps._ -import dotc.core.StdNames._ -import dotc.core.Decorators._ -import dotc.core.Scopes.Scope -import dotc.core.Symbols.{ Symbol, ClassSymbol, defn } -import dotc.core.SymDenotations.NoDenotation -import dotc.core.Types._ -import dotc.printing.Texts._ -import dotc.printing.{ GlobalPrec, DotPrec, Printer, PlainPrinter } -import dotc.typer.Implicits.SearchResult -import dotc.typer.ImportInfo - -// TODO: Avoid code duplication between userfacing and refined printers -class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { - - private def panic(msg: String): Nothing = throw new AssertionError(msg) - - private[this] def getPkgCls(path: String) = - _ctx.requiredPackage(path).moduleClass.asClass - - private lazy val collectionPkg = getPkgCls("scala.collection") - private lazy val immutablePkg = getPkgCls("scala.collection.immutable") - private lazy val scalaPkg = defn.ScalaPackageClass - private lazy val javaLangPkg = defn.JavaLangPackageVal.moduleClass.asClass - - def standardPkg(pkgSym: Symbol) = pkgSym match { - case `scalaPkg` | `collectionPkg` | `immutablePkg` | `javaLangPkg` => true - case _ => false - } - - def wrappedName(pkgSym: Symbol) = - pkgSym.name.toTermName == nme.EMPTY_PACKAGE || - pkgSym.name.isReplWrapperName - - def wellKnownPkg(pkgSym: Symbol) = standardPkg(pkgSym) || wrappedName(pkgSym) - - override protected def keyString(sym: Symbol): String = { - val flags = sym.flags - if (flags is Package) "" - else if (sym.isPackageObject) "package object" - else if (flags.is(Module) && flags.is(Case)) "case object" - else if (sym.isClass && flags.is(Case)) "case class" - else if (flags.is(Lazy)) "lazy val" - else if (flags is Module) "object" - else if (sym.isTerm && !flags.is(Param) && flags.is(Implicit)) "implicit val" - else super.keyString(sym) - } - - override def nameString(name: Name): String = - if (name.isReplAssignName) name.decode.toString.takeWhile(_ != '$') - else name.decode.toString - - override def toText(sym: Symbol): Text = - if (sym.name.isReplAssignName) nameString(sym.name) - else keyString(sym) ~~ nameString(sym.name.stripModuleClassSuffix) - - override def dclText(sym: Symbol): Text = - toText(sym) ~ { - if (sym.is(Method)) toText(sym.info) - else if (sym.isClass) "" - else if (sym.isType && sym.info.isInstanceOf[TypeAlias]) " =" ~~ toText(sym.info) - else if (sym.isType) "" - else { - ":" ~~ toText(sym.info) - } - } - - override def toText(denot: Denotation): Text = denot match { - case NoDenotation => - panic("NoDenotation encountered in UserFacingPrinter") - case denot: MultiDenotation => - panic("MultiDenotation not allowed in UserFacingPrinter") - case _ => - toText(denot.symbol) - } - - override def toText(const: Constant): Text = Str(const.value.toString) - - override def toText(tp: Type): Text = tp match { - case tp: AnnotatedType => toText(tp.tpe) ~~ toText(tp.annot) - case tp: ConstantType => toText(tp.value) - case tp: TypeAlias => toText(tp.underlying) - case ExprType(result) => ":" ~~ toText(result) - case TypeBounds(lo, hi) => - { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ // TODO: that's different from how args are written in source! - { if (hi != defn.AnyType) "<:" ~~ toText(hi) else Text() } - case tp: TypeRef => tp.info match { - case TypeAlias(alias) => toText(alias) - case _ => toText(tp.info) - } - case tp: ParamRef => { - val name = tp.paramName.unexpandedName.invariantName.toString - if (tp.isInstanceOf[TermParamRef]) name ~ ".type" - else name - } - case EtaExpansion(tycon) => toText(tycon) - case PolyType(params, res) => - "[" ~ Fluid(params.map(tl => toText(tl.paramRef)).intersperse(Str(", "))) ~ "]" ~ toText(res) - case tp: MethodType => { - def paramText(name: TermName, tp: Type) = toText(name) ~ ": " ~ toText(tp) - changePrec(GlobalPrec) { - (if (tp.isImplicit) "(implicit " else "(") ~ - Text((tp.paramNames, tp.paramInfos).zipped map paramText, ", ") ~ - (if (tp.resultType.isInstanceOf[MethodType]) ")" else "): ") ~ - toText(tp.resultType) - } - } - case AnyAppliedType(tycon, args) => { - def argText(tp: Type) = - toText { - tp match { - case tp: TypeArgRef => tp.underlying - case _ => tp - } - } - def toTextInfixType(tycon: Type, args: List[Type]): Text = { - // TODO: blatant copy from `RefinedPrinter` - val l :: r :: Nil = args - val isRightAssoc = tycon.typeSymbol.name.endsWith(":") - val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ argText(l) ~ ")" else argText(l) - val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ argText(r) ~ ")" else argText(r) - leftArg ~~ atPrec(DotPrec) { tycon.toText(this) } ~~ rightArg - } - if (tp.isInfixType) toTextInfixType(tycon, args) - else { - toText(tycon) ~ "[" ~ Fluid(args.reverse.map(argText).intersperse(Str(", "))) ~ "]" - } - } - case tp: TypeArgRef => - super.toText(tp) - case tp: ClassInfo => { - if (wellKnownPkg(tp.cls.owner)) - nameString(tp.cls.name) - else { - def printPkg(sym: ClassSymbol): Text = - if (sym.owner == defn.RootClass || wrappedName(sym.owner)) - nameString(sym.name.stripModuleClassSuffix) - else - printPkg(sym.owner.asClass) ~ "." ~ toText(sym) - - printPkg(tp.cls.owner.asClass) ~ "." ~ nameString(tp.cls.name) - } - } - } - - override lazy val plain = new PlainPrinter(_ctx) -} From 99f6bf2e555b70c10e14e4f4aa387bc87ad15ee0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 18:03:17 +0200 Subject: [PATCH 077/146] Use adaptHkVariances when comparing type arguments Used to be done only for refinements. We should see whether we can move the whole logic to eta expansion instead. With the change we can undo a previous change that suppressed variance checking when in Scala 2 mode. --- .../tools/dotc/core/TypeApplications.scala | 11 ++----- .../dotty/tools/dotc/core/TypeComparer.scala | 32 +++++++------------ 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 68c42aa5dc51..4a66a82001d8 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -290,15 +290,8 @@ class TypeApplications(val self: Type) extends AnyVal { self } - /** Convert a type constructor `TC` which has type parameters `T1, ..., Tn` - * in a context where type parameters `U1,...,Un` are expected to - * - * LambdaXYZ { Apply = TC[hk$0, ..., hk$n] } - * - * Here, XYZ corresponds to the variances of - * - `U1,...,Un` if the variances of `T1,...,Tn` are pairwise compatible with `U1,...,Un`, - * - `T1,...,Tn` otherwise. - * v1 is compatible with v2, if v1 = v2 or v2 is non-variant. + /** Convert a type constructor `TC` which has type parameters `X1, ..., Xn` + * to `[X1, ..., Xn] -> TC[X1, ..., Xn]`. */ def EtaExpand(tparams: List[TypeSymbol])(implicit ctx: Context): Type = { val tparamsToUse = if (variancesConform(typeParams, tparams)) tparams else typeParamSymbols diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b15623c2021b..7586a598ff42 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -446,8 +446,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2: HKTypeLambda => def compareTypeLambda: Boolean = tp1.stripTypeVar match { case tp1: HKTypeLambda => - /* Don't compare bounds or variances of lambdas under language:Scala2. - * (1) If we compare bounds, t2994 will fail. + /* Don't compare bounds of lambdas under language:Scala2, or t2994 will fail. * The issue is that, logically, bounds should compare contravariantly, * but that would invalidate a pattern exploited in t2994: * @@ -459,32 +458,17 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * * Note: it would be nice if this could trigger a migration warning, but I * am not sure how, since the code is buried so deep in subtyping logic. - * - * (2) If we compare variances, compilation of scala.collection.mutable.Set wil fail. - * The issue is the following: - * - * Error overriding method companion in trait Iterable of type - * => scala.collection.generic.GenericCompanion[[+A] => scala.collection.Iterable[A]]; - * method companion of type - * => scala.collection.generic.GenericCompanion[[A] => scala.collection.mutable.Set[A]] - * has incompatible type. - * - * Indeed, a non-variant Set is not a legal substitute for a covariant Iterable. - * Every instantiated Set is an Iterable, but the type constructor Iterable can be - * passed to a covariant type constructor CC[+X] whereas a non-variant Set cannot. */ def boundsOK = ctx.scala2Mode || tp1.typeParams.corresponds(tp2.typeParams)((tparam1, tparam2) => isSubType(tparam2.paramInfo.subst(tp2, tp1), tparam1.paramInfo)) - def variancesOK = - ctx.scala2Mode || - variancesConform(tp1.typeParams, tp2.typeParams) val saved = comparedTypeLambdas comparedTypeLambdas += tp1 comparedTypeLambdas += tp2 try - variancesOK && boundsOK && + variancesConform(tp1.typeParams, tp2.typeParams) && + boundsOK && isSubType(tp1.resType, tp2.resType.subst(tp2, tp1)) finally comparedTypeLambdas = saved case _ => @@ -1014,7 +998,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { } } - isSubArg(args1.head, args2.head) + val arg1 = args1.head + val arg2 = args2.head + isSubArg(arg1, arg2) || { + // last effort: try to adapt variances of higher-kinded types if this is sound. + // TODO: Move this to eta-expansion? + val adapted2 = arg2.adaptHkVariances(tparam.paramInfo) + adapted2.ne(arg2) && isSubArg(arg1, adapted2) + } } && isSubArgs(args1.tail, args2.tail, tp1, tparams.tail) /** Test whether `tp1` has a base type of the form `B[T1, ..., Tn]` where @@ -1186,6 +1177,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { def hasSubRefinement(tp1: RefinedType, refine2: Type): Boolean = { isSubType(tp1.refinedInfo, refine2) || { // last effort: try to adapt variances of higher-kinded types if this is sound. + // TODO: Move this to eta-expansion? val adapted2 = refine2.adaptHkVariances(tp1.parent.member(tp1.refinedName).symbol.info) adapted2.ne(refine2) && hasSubRefinement(tp1, adapted2) } From 0db4ed4c9a049ce19534c2b429c0eff8fa8c9923 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 19:24:46 +0200 Subject: [PATCH 078/146] Re-apply change to printing TypeArgRefs in UserfacingPrinter --- .../src/dotty/tools/dotc/printing/UserFacingPrinter.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/printing/UserFacingPrinter.scala b/compiler/src/dotty/tools/dotc/printing/UserFacingPrinter.scala index 23ea813b6e81..0b0bbe13f47b 100644 --- a/compiler/src/dotty/tools/dotc/printing/UserFacingPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/UserFacingPrinter.scala @@ -47,6 +47,11 @@ class UserFacingPrinter(_ctx: Context) extends RefinedPrinter(_ctx) { override def toText(const: Constant): Text = Str(const.value.toString) + override def argText(tp: Type): Text = tp match { + case arg: TypeArgRef => argText(arg.underlying) + case _ => super.argText(tp) + } + override def toText(tp: Type): Text = tp match { case ExprType(result) => ":" ~~ toText(result) case tp: ConstantType => toText(tp.value) From 0fd92dab1f4750f2414d64207a57f74b65c0bfb9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 20:50:06 +0200 Subject: [PATCH 079/146] Fix script check file Since the declared result type of typle2Shape has (P1, P2) as last argument, I fail to see how an instance of it could print (). (_, _) seems more plausible. --- compiler/test-resources/repl/i2554 | 2 +- tests/pending/pos/i2671.scala | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/pending/pos/i2671.scala diff --git a/compiler/test-resources/repl/i2554 b/compiler/test-resources/repl/i2554 index b8d88dee119c..10fda5a7a780 100644 --- a/compiler/test-resources/repl/i2554 +++ b/compiler/test-resources/repl/i2554 @@ -4,4 +4,4 @@ scala> import foo._ scala> implicit val shape: Shape[_ <: FlatShapeLevel, Int, Int, _] = null implicit val shape: foo.Shape[_ <: foo.FlatShapeLevel, Int, Int, _] = null scala> def hint = Shape.tuple2Shape(shape, shape) -def hint: foo.Shape[foo.FlatShapeLevel, (Int, Int), (Int, Int), ()] +def hint: foo.Shape[foo.FlatShapeLevel, (Int, Int), (Int, Int), (_, _)] diff --git a/tests/pending/pos/i2671.scala b/tests/pending/pos/i2671.scala new file mode 100644 index 000000000000..de942b4f9799 --- /dev/null +++ b/tests/pending/pos/i2671.scala @@ -0,0 +1,11 @@ +object Foo { + + def map[E](f: implicit E => Int): (implicit E => Int) = ??? + + implicit def i: Int = ??? + + def f: implicit Int => Int = ??? + + val a: Int = map(f) + +} From 871a178c66438372385faaa6b0a0d6654d0c028a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 21:07:28 +0200 Subject: [PATCH 080/146] Drop HKApply --- .../tools/dotc/core/SymDenotations.scala | 1 - .../tools/dotc/core/TypeApplications.scala | 19 +- .../dotty/tools/dotc/core/TypeComparer.scala | 163 ----------------- .../dotty/tools/dotc/core/TypeErasure.scala | 9 +- .../src/dotty/tools/dotc/core/Types.scala | 171 +----------------- .../core/unpickleScala2/Scala2Unpickler.scala | 8 - .../tools/dotc/printing/PlainPrinter.scala | 4 - .../tools/dotc/transform/patmat/Space.scala | 2 - .../src/dotty/tools/dotc/typer/Checking.scala | 13 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../dotty/tools/dotc/typer/ProtoTypes.scala | 5 - .../dotty/tools/dotc/typer/Variances.scala | 11 -- .../tools/dottydoc/model/factories.scala | 2 +- 13 files changed, 21 insertions(+), 389 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index e5bf2c197d07..142547f926ae 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1175,7 +1175,6 @@ object SymDenotations { case tp: TypeVar => hasSkolems(tp.inst) case tp: ExprType => hasSkolems(tp.resType) case tp: AppliedType => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) - case tp: HKApply => hasSkolems(tp.tycon) || tp.args.exists(hasSkolems) case tp: LambdaType => tp.paramInfos.exists(hasSkolems) || hasSkolems(tp.resType) case tp: AndOrType => hasSkolems(tp.tp1) || hasSkolems(tp.tp2) case tp: AnnotatedType => hasSkolems(tp.tpe) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 4a66a82001d8..862c49b84e09 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -75,7 +75,7 @@ object TypeApplications { * * where v_i, p_i are the variances and names of the type parameters of T. */ - object AnyAppliedType { + object AnyAppliedType { // @!!! drop 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 { @@ -101,8 +101,6 @@ object TypeApplications { collectArgs(tycon.typeParams, refinements, new mutable.ListBuffer[Type]) case AppliedType(tycon, args) => Some((tycon, args)) - case HKApply(tycon, args) => - Some((tycon, args)) case _ => None } @@ -186,7 +184,7 @@ object TypeApplications { case arg => arg } - case _: TypeBounds | _: HKApply | _: AppliedType => + case _: TypeBounds | _: AppliedType => val saved = available available = Set() try mapOver(t) @@ -229,7 +227,7 @@ class TypeApplications(val self: Type) extends AnyVal { Nil case self: WildcardType => self.optBounds.typeParams - case self: AppliedType => + case self: AppliedType if self.tycon.typeSymbol.isClass => Nil case self: TypeProxy => self.superType.typeParams @@ -412,7 +410,7 @@ class TypeApplications(val self: Type) extends AnyVal { } } if ((dealiased eq stripped) || followAlias) dealiased.instantiate(args) - else HKApply(self, args) + else AppliedType(self, args) } else dealiased.resType match { case AnyAppliedType(tycon, args1) if tycon.safeDealias ne tycon => @@ -425,7 +423,7 @@ class TypeApplications(val self: Type) extends AnyVal { val reducer = new Reducer(dealiased, args) val reduced = reducer(dealiased.resType) if (reducer.allReplaced) reduced - else HKApply(dealiased, args) + else AppliedType(dealiased, args) } tryReduce case dealiased: PolyType => @@ -442,8 +440,6 @@ class TypeApplications(val self: Type) extends AnyVal { WildcardType(dealiased.optBounds.appliedTo(args).bounds) case dealiased: TypeRef if dealiased.symbol == defn.NothingClass => dealiased - case _ if typParams.isEmpty || typParams.head.isInstanceOf[LambdaParam] => - HKApply(self, args) case dealiased => AppliedType(self, args) } @@ -462,7 +458,7 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def safeAppliedTo(args: List[Type])(implicit ctx: Context) = self match { case self: TypeRef if !self.symbol.isClass && self.symbol.isCompleting => - HKApply(self, args) + AppliedType(self, args) case _ => appliedTo(args) } @@ -529,8 +525,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** The core type without any type arguments. * @param `typeArgs` must be the type arguments of this type. */ - final def withoutArgs(typeArgs: List[Type]): Type = self match { - case HKApply(tycon, args) => tycon + final def withoutArgs(typeArgs: List[Type]): Type = self match { // @!!! replace with typeConstructor? case AppliedType(tycon, args) => tycon case _ => typeArgs match { diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 7586a598ff42..51054c96ff96 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -336,12 +336,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { else thirdTry(tp1, tp2) case tp1 @ OrType(tp11, tp12) => def joinOK = tp2.dealias match { - case _: HKApply => - // If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a - // type parameter, we will instantiate `C` to `A` and then fail when comparing - // with `B[Y]`. To do the right thing, we need to instantiate `C` to the - // common superclass of `A` and `B`. - isSubType(tp1.join, tp2) case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass => isSubType(tp1.join, tp2) case _ => @@ -441,8 +435,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { isSubType(fixRecs(tp1stable, tp1stable.widenExpr), tp2.parent.substRecThis(tp2, tp1stable)) } compareRec - case tp2 @ HKApply(tycon2, args2) => - compareHkApply2(tp1, tp2, tycon2, args2) case tp2: HKTypeLambda => def compareTypeLambda: Boolean = tp1.stripTypeVar match { case tp1: HKTypeLambda => @@ -602,8 +594,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { isNewSubType(tp1.parent, tp2) case tp1: TypeArgRef => isSubType(tp1.underlying.hiBound, tp2) - case tp1 @ HKApply(tycon1, args1) => - compareHkApply1(tp1, tycon1, args1, tp2) case tp1: HKTypeLambda => def compareHKLambda = tp1 match { case EtaExpansion(tycon1) => isSubType(tycon1, tp2) @@ -647,159 +637,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { false } - /** Subtype test for the hk application `tp2 = tycon2[args2]`. - */ - def compareHkApply2(tp1: Type, tp2: HKApply, tycon2: Type, args2: List[Type]): Boolean = { - val tparams = tycon2.typeParams - if (tparams.isEmpty) return false // can happen for ill-typed programs, e.g. neg/tcpoly_overloaded.scala - - /** True if `tp1` and `tp2` have compatible type constructors and their - * corresponding arguments are subtypes relative to their variance (see `isSubArgs`). - */ - def isMatchingApply(tp1: Type): Boolean = tp1 match { - case HKApply(tycon1, args1) => - tycon1.dealias match { - case tycon1: TypeParamRef => - (tycon1 == tycon2 || - canConstrain(tycon1) && tryInstantiate(tycon1, tycon2)) && - isSubArgs(args1, args2, tp1, tparams) - case tycon1: TypeRef => - tycon2.dealias match { - case tycon2: TypeRef if tycon1.symbol == tycon2.symbol => - isSubType(tycon1.prefix, tycon2.prefix) && - isSubArgs(args1, args2, tp1, tparams) - case _ => - false - } - case tycon1: TypeVar => - isMatchingApply(tycon1.underlying) - case tycon1: AnnotatedType => - isMatchingApply(tycon1.underlying) - case _ => - false - } - case _ => - false - } - - /** `param2` can be instantiated to a type application prefix of the LHS - * or to a type application prefix of one of the LHS base class instances - * and the resulting type application is a supertype of `tp1`, - * or fallback to fourthTry. - */ - def canInstantiate(tycon2: TypeParamRef): Boolean = { - - /** Let - * - * `tparams_1, ..., tparams_k-1` be the type parameters of the rhs - * `tparams1_1, ..., tparams1_n-1` be the type parameters of the constructor of the lhs - * `args1_1, ..., args1_n-1` be the type arguments of the lhs - * `d = n - k` - * - * Returns `true` iff `d >= 0` and `tycon2` can be instantiated to - * - * [tparams1_d, ... tparams1_n-1] -> tycon1a[args_1, ..., args_d-1, tparams_d, ... tparams_n-1] - * - * such that the resulting type application is a supertype of `tp1`. - */ - def tyconOK(tycon1a: Type, args1: List[Type]) = { - var tycon1b = tycon1a - val tparams1a = tycon1a.typeParams - val lengthDiff = tparams1a.length - tparams.length - lengthDiff >= 0 && { - val tparams1 = tparams1a.drop(lengthDiff) - variancesConform(tparams1, tparams) && { - if (lengthDiff > 0) - tycon1b = HKTypeLambda(tparams1.map(_.paramName))( - tl => tparams1.map(tparam => tl.integrate(tparams, tparam.paramInfo).bounds), - tl => tycon1a.appliedTo(args1.take(lengthDiff) ++ - tparams1.indices.toList.map(tl.paramRefs(_)))) - (ctx.mode.is(Mode.TypevarsMissContext) || - tryInstantiate(tycon2, tycon1b.ensureHK)) && - isSubType(tp1, tycon1b.appliedTo(args2)) - } - } - } - - tp1.widen match { - case tp1w @ HKApply(tycon1, args1) => - tyconOK(tycon1, args1) - case tp1w => - tp1w.typeSymbol.isClass && { - val classBounds = tycon2.classSymbols - def liftToBase(bcs: List[ClassSymbol]): Boolean = bcs match { - case bc :: bcs1 => - classBounds.exists(bc.derivesFrom) && - tyconOK(tp1w.baseTypeTycon(bc), tp1w.baseArgInfos(bc)) || - liftToBase(bcs1) - case _ => - false - } - liftToBase(tp1w.baseClasses) - } || - fourthTry(tp1, tp2) - } - } - - /** Fall back to comparing either with `fourthTry` or against the lower - * approximation of the rhs. - * @param tyconLo The type constructor's lower approximation. - */ - def fallback(tyconLo: Type) = - either(fourthTry(tp1, tp2), isSubType(tp1, tyconLo.applyIfParameterized(args2))) - - /** Let `tycon2bounds` be the bounds of the RHS type constructor `tycon2`. - * Let `app2 = tp2` where the type constructor of `tp2` is replaced by - * `tycon2bounds.lo`. - * If both bounds are the same, continue with `tp1 <:< app2`. - * otherwise continue with either - * - * tp1 <:< tp2 using fourthTry (this might instantiate params in tp1) - * tp1 <:< app2 using isSubType (this might instantiate params in tp2) - */ - def compareLower(tycon2bounds: TypeBounds, tyconIsTypeRef: Boolean): Boolean = - if (tycon2bounds.lo eq tycon2bounds.hi) - isSubType(tp1, - if (tyconIsTypeRef) tp2.superType - else tycon2bounds.lo.applyIfParameterized(args2)) - else - fallback(tycon2bounds.lo) - - tycon2 match { - case param2: TypeParamRef => - isMatchingApply(tp1) || - canConstrain(param2) && canInstantiate(param2) || - compareLower(bounds(param2), tyconIsTypeRef = false) - case tycon2: TypeRef => - isMatchingApply(tp1) || - compareLower(tycon2.info.bounds, tyconIsTypeRef = true) - case _: TypeVar | _: AnnotatedType => - isSubType(tp1, tp2.superType) - case tycon2: HKApply => - fallback(tycon2.lowerBound) - case _ => - false - } - } - - /** Subtype test for the hk application `tp1 = tycon1[args1]`. - */ - def compareHkApply1(tp1: HKApply, tycon1: Type, args1: List[Type], tp2: Type): Boolean = - tycon1 match { - case param1: TypeParamRef => - def canInstantiate = tp2 match { - case AnyAppliedType(tycon2, args2) => - tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tp1, tycon2.typeParams) - case _ => - false - } - canConstrain(param1) && canInstantiate || - isSubType(bounds(param1).hi.applyIfParameterized(args1), tp2) - case tycon1: TypeProxy => - isSubType(tp1.superType, tp2) - case _ => - false - } /** Subtype test for the hk application `tp2 = tycon2[args2]`. */ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index b231ca1b0d66..ddcbe2c0061f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -396,8 +396,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean defn.FunctionType(0) case AndType(tp1, tp2) => erasedGlb(this(tp1), this(tp2), isJava) - case tp: HKApply => - apply(tp.superType) case OrType(tp1, tp2) => ctx.typeComparer.orType(this(tp1), this(tp2), erased = true) case tp: MethodType => @@ -532,13 +530,14 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else normalizeClass(sym.asClass).fullName.asTypeName case tp: AppliedType => - sigName(if (tp.tycon.isRef(defn.ArrayClass)) this(tp) else tp.underlying) + sigName( + if (tp.tycon.isRef(defn.ArrayClass)) this(tp) + else if (tp.tycon.typeSymbol.isClass) tp.underlying + else tp.superType) case ErasedValueType(_, underlying) => sigName(underlying) case defn.ArrayOf(elem) => // @!!! sigName(this(tp)) - case tp: HKApply => - sigName(tp.superType) case JavaArrayType(elem) => sigName(elem) ++ "[]" case tp: TermRef => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bc311ef41f1c..f46443f62e41 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -62,7 +62,7 @@ object Types { * | +- TypeParamRef * | +- RefinedOrRecType -+-- RefinedType * | | -+-- RecType - * | +- HKApply + * | +- AppliedType * | +- TypeBounds * | +- ExprType * | +- AnnotatedType @@ -131,15 +131,12 @@ object Types { tp.isRef(sym) case _ => this1.symbol eq sym } - case this1: RefinedOrRecType => this1.parent.isRef(sym) + case this1: RefinedOrRecType => + this1.parent.isRef(sym) case this1: AppliedType => val this2 = this1.dealias if (this2 ne this1) this2.isRef(sym) else this1.underlying.isRef(sym) - case this1: HKApply => - val this2 = this1.dealias - if (this2 ne this1) this2.isRef(sym) - else this1.underlying.isRef(sym) case _ => false } @@ -516,8 +513,6 @@ object Types { goParam(tp) case tp: SuperType => goSuper(tp) - case tp: HKApply => - goHKApply(tp) case tp: TypeProxy => go(tp.underlying) case tp: ClassInfo => @@ -605,14 +600,6 @@ object Types { 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)) - case _ => - go(tp.superType) - } - def goThis(tp: ThisType) = { val d = go(tp.underlying) if (d.exists) d @@ -1000,10 +987,6 @@ object Types { 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 @@ -3134,11 +3117,11 @@ object Types { // supertype not stable, since underlying might change validSuper = Nowhere tycon.underlying.applyIfParameterized(args) + case tycon: TypeRef if tycon.symbol.isClass => + tycon case tycon: TypeProxy => - val sym = tycon.typeSymbol - if (sym.is(Provisional)) validSuper = Nowhere - if (sym.isClass) tycon - else tycon.superType.applyIfParameterized(args) + if (tycon.typeSymbol.is(Provisional)) validSuper = Nowhere + tycon.superType.applyIfParameterized(args) case _ => defn.AnyType } } @@ -3187,79 +3170,6 @@ object Types { } } - /** A higher kinded type application `C[T_1, ..., T_n]` */ - abstract case class HKApply(tycon: Type, args: List[Type]) - extends CachedProxyType with ValueType { - - private var validSuper: Period = Nowhere - private var cachedSuper: Type = _ - - override def underlying(implicit ctx: Context): Type = tycon - - override def superType(implicit ctx: Context): Type = { - 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 - tp.underlying.applyIfParameterized(args) - case tp: TypeProxy => - if (tp.typeSymbol.is(Provisional)) validSuper = Nowhere - tp.superType.applyIfParameterized(args) - case _ => defn.AnyType - } - } - cachedSuper - } - - 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 if !tycon.symbol.isClass => - 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 CachedHKApply(tycon: Type, args: List[Type]) extends HKApply(tycon, args) - - object HKApply { - def apply(tycon: Type, args: List[Type])(implicit ctx: Context) = - unique(new CachedHKApply(tycon, args)).checkInst - } - /** A reference to wildcard argument `p.` * where `p: C[... _ ...]` */ @@ -3892,8 +3802,6 @@ object Types { zeroParamClass(tp.underlying) case tp: TypeVar => zeroParamClass(tp.underlying) - case tp: HKApply => - zeroParamClass(tp.superType) case _ => NoType } @@ -3969,8 +3877,6 @@ object Types { tp.derivedSuperType(thistp, supertp) protected def derivedAppliedType(tp: AppliedType, tycon: Type, args: List[Type]): Type = tp.derivedAppliedType(tycon, args) - protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = - tp.derivedAppliedType(tycon, args) protected def derivedTypeArgRef(tp: TypeArgRef, prefix: Type): Type = tp.derivedTypeArgRef(prefix) protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type): Type = @@ -4036,12 +3942,6 @@ object Types { val inst = tp.instanceOpt if (inst.exists) apply(inst) else tp - case tp: HKApply => - def mapArg(arg: Type, tparam: ParamInfo): Type = - atVariance(variance * tparam.paramVariance)(this(arg)) - derivedAppliedType(tp, this(tp.tycon), - tp.args.zipWithConserve(tp.typeParams)(mapArg)) - case tp: ExprType => derivedExprType(tp, this(tp.resultType)) @@ -4311,46 +4211,6 @@ object Types { else tp.derivedAppliedType(tycon, args) } - override protected def derivedAppliedType(tp: HKApply, tycon: Type, args: List[Type]): Type = - tycon match { - case Range(tyconLo, tyconHi) => - range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args)) - case _ => - if (args.exists(isRange)) { - if (variance > 0) tp.derivedAppliedType(tycon, args.map(rangeToBounds)) - else { - val loBuf, hiBuf = new mutable.ListBuffer[Type] - // Given `C[A1, ..., An]` where sone A's are ranges, try to find - // non-range arguments L1, ..., Ln and H1, ..., Hn such that - // C[L1, ..., Ln] <: C[H1, ..., Hn] by taking the right limits of - // ranges that appear in as co- or contravariant arguments. - // Fail for non-variant argument ranges. - // If successful, the L-arguments are in loBut, the H-arguments in hiBuf. - // @return operation succeeded for all arguments. - def distributeArgs(args: List[Type], tparams: List[ParamInfo]): Boolean = args match { - case Range(lo, hi) :: args1 => - val v = tparams.head.paramVariance - if (v == 0) false - else { - if (v > 0) { loBuf += lo; hiBuf += hi } - else { loBuf += hi; hiBuf += lo } - distributeArgs(args1, tparams.tail) - } - case arg :: args1 => - loBuf += arg; hiBuf += arg - distributeArgs(args1, tparams.tail) - case nil => - true - } - if (distributeArgs(args, tp.typeParams)) - range(tp.derivedAppliedType(tycon, loBuf.toList), - tp.derivedAppliedType(tycon, hiBuf.toList)) - else range(tp.bottomType, tp.topType) - // TODO: can we give a better bound than `topType`? - } - } - else tp.derivedAppliedType(tycon, args) - } override protected def derivedAndOrType(tp: AndOrType, tp1: Type, tp2: Type) = if (isRange(tp1) || isRange(tp2)) if (tp.isAnd) range(lower(tp1) & lower(tp2), upper(tp1) & upper(tp2)) @@ -4478,23 +4338,6 @@ object Types { case tp @ ClassInfo(prefix, _, _, _, _) => this(x, prefix) - case tp @ HKApply(tycon, args) => - @tailrec def foldArgs(x: T, tparams: List[ParamInfo], args: List[Type]): T = - if (args.isEmpty) { - assert(tparams.isEmpty) - x - } - else { - val tparam = tparams.head - val saved = variance - variance *= tparam.paramVariance - val acc = - try this(x, args.head) - finally variance = saved - foldArgs(acc, tparams.tail, args.tail) - } - foldArgs(this(x, tycon), tp.typeParams, args) - case tp: LambdaType => variance = -variance val y = foldOver(x, tp.paramInfos) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 6a5236a7d25a..69531b8fd464 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -660,14 +660,6 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case info => tp.derivedRefinedType(parent1, name, info) } - case tp @ HKApply(tycon, args) => - val tycon1 = tycon.safeDealias - def mapArg(arg: Type) = arg match { - case arg: TypeRef if isBound(arg) => arg.symbol.info - case _ => arg - } - if (tycon1 ne tycon) elim(tycon1.appliedTo(args)) - else tp.derivedAppliedType(tycon, args.map(mapArg)) case tp @ AppliedType(tycon, args) => val tycon1 = tycon.safeDealias def mapArg(arg: Type) = arg match { diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index d61b49536ee7..602b095fe43e 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -64,8 +64,6 @@ class PlainPrinter(_ctx: Context) extends Printer { homogenize(tp.ref) case AppliedType(tycon, args) => tycon.dealias.appliedTo(args) - case HKApply(tycon, args) => - tycon.dealias.appliedTo(args) case _ => tp } @@ -208,8 +206,6 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tpe) ~ " " ~ toText(annot) case AppliedType(tycon, args) => toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" - case HKApply(tycon, args) => - toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" case tp: TypeVar => if (tp.isInstantiated) toTextLocal(tp.instanceOpt) ~ ("^" provided ctx.settings.YprintDebug.value) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index fac200b71fb9..4e2f87cebc36 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -430,7 +430,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { def erase(tp: Type): Type = { def doErase(tp: Type): Type = tp match { case tp: AppliedType => erase(tp.superType) - case tp: HKApply => erase(tp.superType) case tp: RefinedType => erase(tp.parent) case _ => tp } @@ -569,7 +568,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { debug.println(i"refine($tp1, $tp2) = $res") res case (tp1: AppliedType, _) => refine(tp1.superType, tp2) - case (tp1: HKApply, _) => refine(tp1.superType, tp2) case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) => if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2 case (TypeRef(ref1: TypeProxy, _), tp2 @ TermRef(ref2: TypeProxy, _)) => diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index df3c85259174..248144e6048e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -93,15 +93,6 @@ object Checking { case _ => checkWildcardApply(tp.superType, pos) } - case tp @ HKApply(tycon, args) if args.exists(_.isInstanceOf[TypeBounds]) => - tycon match { - case tycon: TypeLambda => - ctx.errorOrMigrationWarning( - ex"unreducible application of higher-kinded type $tycon to wildcard arguments", - pos) - case _ => - checkWildcardApply(tp.superType, pos) - } case _ => } def checkValidIfApply(implicit ctx: Context): Unit = @@ -228,8 +219,6 @@ object Checking { tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK)) case tp: RecType => tp.rebind(this(tp.parent)) - case tp @ HKApply(tycon, args) => - tp.derivedAppliedType(this(tycon), args.map(this(_, nestedCycleOK, nestedCycleOK))) case tp @ TypeRef(pre, name) => try { // A prefix is interesting if it might contain (transitively) a reference @@ -245,7 +234,7 @@ object Checking { case SuperType(thistp, _) => isInteresting(thistp) case AndType(tp1, tp2) => isInteresting(tp1) || isInteresting(tp2) case OrType(tp1, tp2) => isInteresting(tp1) && isInteresting(tp2) - case _: RefinedOrRecType | _: HKApply | _: AppliedType => true + case _: RefinedOrRecType | _: AppliedType => true case _ => false } if (isInteresting(pre)) { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 06b933c21d6e..c0e1967ede28 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -386,7 +386,7 @@ trait ImplicitRunInfo { self: RunInfo => (lead /: tp.classSymbols)(joinClass) case tp: TypeVar => apply(tp.underlying) - case tp: HKApply => // @!!! needed? + case tp: AppliedType if !tp.tycon.typeSymbol.isClass => def applyArg(arg: Type) = arg match { case TypeBounds(lo, hi) => AndType.make(lo, hi) case _: WildcardType => defn.AnyType diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 5f71281eaa1a..9f36fbed9d34 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -507,11 +507,6 @@ object ProtoTypes { WildcardType(TypeBounds.upper(wildApprox(mt.paramInfos(pnum), theMap, seen))) case tp: TypeVar => wildApprox(tp.underlying, theMap, seen) - case tp @ HKApply(tycon, args) => - wildApprox(tycon, theMap, seen) match { - case _: WildcardType => WildcardType // this ensures we get a * type - case tycon1 => tp.derivedAppliedType(tycon1, args.mapConserve(wildApprox(_, theMap, seen))) - } case tp: AndType => def approxAnd = { val tp1a = wildApprox(tp.tp1, theMap, seen) diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index 20fadccc3d7d..d9519ce51786 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -94,17 +94,6 @@ object Variances { v } varianceInArgs(varianceInType(tycon)(tparam), args, tycon.typeParams) - case tp @ HKApply(tycon, args) => - def varianceInArgs(v: Variance, args: List[Type], tparams: List[ParamInfo]): Variance = - args match { - case arg :: args1 => - varianceInArgs( - v & compose(varianceInType(arg)(tparam), tparams.head.paramVariance), - args1, tparams.tail) - case nil => - v - } - varianceInArgs(varianceInType(tycon)(tparam), args, tycon.typeParams) case AnnotatedType(tp, annot) => varianceInType(tp)(tparam) & varianceInAnnot(annot)(tparam) case tp: AndOrType => diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index e045bf84a4ca..8ad26b5cc8ef 100644 --- a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala +++ b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala @@ -176,7 +176,7 @@ object factories { paramLists(annot.tpe) case (_: TypeParamRef | _: RefinedType | _: TypeRef | _: ThisType | - _: ExprType | _: OrType | _: AndType | _: HKApply | _: AppliedType | + _: ExprType | _: OrType | _: AndType | _: AppliedType | _: TermRef | _: ConstantType) => Nil // return types should not be in the paramlist } From cdb34e5a4eca7f9a8cd1683fd56436c78f40dd21 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 21:10:08 +0200 Subject: [PATCH 081/146] Make baseTypeOf more robust After the last commit i1650.scala crashed when trying to substitute mismatched type parameter / argument lists. This happened because we took a baseType of class Nothing. That case should be supported, so we need to compare the length of type parameters vs arguments before trying a substitution here. --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 142547f926ae..f7e8a0605700 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1661,7 +1661,9 @@ object SymDenotations { if (subsym eq symbol) tp else subsym.denot match { case clsd: ClassDenotation => - baseTypeOf(tycon).subst(clsd.typeParams, args) + val tparams = clsd.typeParams + if (tparams.hasSameLengthAs(args)) baseTypeOf(tycon).subst(tparams, args) + else NoType case _ => baseTypeOf(tp.superType) } From babc49059a245550dcea888d64686163e6edc3b4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 22:31:14 +0200 Subject: [PATCH 082/146] Drop uniqueRefinedType and uniqueTypeAlias With the change to native applied types, both are now quite rare, so no need for special casing their allocation. --- .../src/dotty/tools/dotc/core/Contexts.scala | 12 +--- .../src/dotty/tools/dotc/core/Types.scala | 26 +++----- .../src/dotty/tools/dotc/core/Uniques.scala | 61 ------------------- 3 files changed, 9 insertions(+), 90 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 28915f9c830c..df330c4da0b5 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -608,24 +608,16 @@ object Contexts { override def hash(x: Type): Int = x.hash } - /** A table for hash consing unique refined types */ - private[dotc] val uniqueRefinedTypes = new RefinedUniques // @!!! replace with uniqueAppliedTypes - - /** A table for hash consing unique refined types */ + /** A table for hash consing unique applied types */ private[dotc] val uniqueAppliedTypes = new AppliedUniques /** A table for hash consing unique named types */ private[core] val uniqueNamedTypes = new NamedTypeUniques - /** A table for hash consing unique type bounds */ - private[core] val uniqueTypeAliases = new TypeAliasUniques // @!!! replace - private def uniqueSets = Map( "uniques" -> uniques, - "uniqueRefinedTypes" -> uniqueRefinedTypes, "uniqueAppliedTypes" -> uniqueAppliedTypes, - "uniqueNamedTypes" -> uniqueNamedTypes, - "uniqueTypeAliases" -> uniqueTypeAliases) + "uniqueNamedTypes" -> uniqueNamedTypes) /** A map that associates label and size of all uniques sets */ def uniquesSizes: Map[String, Int] = uniqueSets.mapValues(_.size) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f46443f62e41..bdaf4478b144 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2293,23 +2293,11 @@ object Types { if (parent.member(refinedName).exists) derivedRefinedType(parent, refinedName, refinedInfo) else parent - override def equals(that: Any) = that match { - case that: RefinedType => - this.parent == that.parent && - this.refinedName == that.refinedName && - this.refinedInfo == that.refinedInfo - case _ => - false - } override def computeHash = doHash(refinedName, refinedInfo, parent) - override def toString = s"RefinedType($parent, $refinedName, $refinedInfo)" } - class CachedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type, hc: Int) - extends RefinedType(parent, refinedName, refinedInfo) { - myHash = hc - override def computeHash = unsupported("computeHash") - } + class CachedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type) + extends RefinedType(parent, refinedName, refinedInfo) object RefinedType { @tailrec def make(parent: Type, names: List[Name], infos: List[Type])(implicit ctx: Context): Type = @@ -2318,7 +2306,7 @@ object Types { def apply(parent: Type, name: Name, info: Type)(implicit ctx: Context): RefinedType = { assert(!ctx.erasedTypes) - ctx.base.uniqueRefinedTypes.enterIfNew(parent, name, info).checkInst + unique(new CachedRefinedType(parent, name, info)).checkInst } } @@ -3662,12 +3650,12 @@ object Types { if (variance == 0) this else if (variance < 0) TypeBounds.lower(alias) else TypeBounds.upper(alias) - } - class CachedTypeAlias(alias: Type, variance: Int, hc: Int) extends TypeAlias(alias, variance) { - myHash = hc + override def computeHash = doHash(variance, alias) } + class CachedTypeAlias(alias: Type, variance: Int) extends TypeAlias(alias, variance) + object TypeBounds { def apply(lo: Type, hi: Type)(implicit ctx: Context): TypeBounds = unique(new RealTypeBounds(lo, hi)) @@ -3678,7 +3666,7 @@ object Types { object TypeAlias { def apply(alias: Type, variance: Int = 0)(implicit ctx: Context) = - ctx.uniqueTypeAliases.enterIfNew(alias, variance) + unique(new CachedTypeAlias(alias, variance)) def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias) } diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index a8c325995ab5..6e80f519868a 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -66,32 +66,6 @@ object Uniques { } } - final class TypeAliasUniques extends HashSet[TypeAlias](Config.initialUniquesCapacity) with Hashable { - override def hash(x: TypeAlias): Int = x.hash - - private def findPrevious(h: Int, alias: Type, variance: Int): TypeAlias = { - var e = findEntryByHash(h) - while (e != null) { - if ((e.alias eq alias) && (e.variance == variance)) return e - e = nextEntryByHash(h) - } - e - } - - def enterIfNew(alias: Type, variance: Int): TypeAlias = { - val h = doHash(variance, alias) - if (monitored) recordCaching(h, classOf[TypeAlias]) - def newAlias = new CachedTypeAlias(alias, variance, h) - if (h == NotCached) newAlias - else { - val r = findPrevious(h, alias, variance) - if (r ne null) r - else addEntryAfterScan(newAlias) - } - } - } - - final class AppliedUniques extends HashSet[AppliedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: AppliedType): Int = x.hash @@ -121,39 +95,4 @@ object Uniques { } } } - - final class RefinedUniques extends HashSet[RefinedType](Config.initialUniquesCapacity) with Hashable { - override val hashSeed = classOf[CachedRefinedType].hashCode // some types start life as CachedRefinedTypes, need to have same hash seed - override def hash(x: RefinedType): Int = x.hash - - private def findPrevious(h: Int, parent: Type, refinedName: Name, refinedInfo: Type): RefinedType = { - var e = findEntryByHash(h) - while (e != null) { - if ((e.parent eq parent) && (e.refinedName eq refinedName) && (e.refinedInfo eq refinedInfo)) - return e - e = nextEntryByHash(h) - } - e - } - - def enterIfNew(parent: Type, refinedName: Name, refinedInfo: Type): RefinedType = { - val h = doHash(refinedName, refinedInfo, parent) - def newType = new CachedRefinedType(parent, refinedName, refinedInfo, h) - if (monitored) recordCaching(h, classOf[CachedRefinedType]) - if (h == NotCached) newType - else { - val r = findPrevious(h, parent, refinedName, refinedInfo) - if (r ne null) r else addEntryAfterScan(newType) - } - } - - def enterIfNew(rt: RefinedType) = { - if (monitored) recordCaching(rt) - if (rt.hash == NotCached) rt - else { - val r = findPrevious(rt.hash, rt.parent, rt.refinedName, rt.refinedInfo) - if (r ne null) r else addEntryAfterScan(rt) - } - } - } } From a78c26f9f5abe456c8ee99e93a3c416abd56ef94 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 31 Aug 2017 23:08:38 +0200 Subject: [PATCH 083/146] Drop variance in TypeAlias --- .../tools/dotc/core/TypeApplications.scala | 15 ++-- .../dotty/tools/dotc/core/TypeComparer.scala | 15 +--- .../src/dotty/tools/dotc/core/TypeOps.scala | 2 - .../src/dotty/tools/dotc/core/Types.scala | 81 ++++--------------- .../tools/dotc/core/tasty/TastyFormat.scala | 6 +- .../tools/dotc/core/tasty/TreePickler.scala | 9 +-- .../tools/dotc/core/tasty/TreeUnpickler.scala | 11 +-- .../tools/dotc/printing/PlainPrinter.scala | 6 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 5 +- .../dotty/tools/dotc/typer/Variances.scala | 2 +- tests/pos/Patterns.scala | 3 +- 12 files changed, 38 insertions(+), 119 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 862c49b84e09..2329fad9e995 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -382,7 +382,7 @@ class TypeApplications(val self: Type) extends AnyVal { case arg :: args1 => try { val tparam :: tparams1 = tparams - matchParams(RefinedType(t, tparam.paramName, arg.toBounds(tparam)), tparams1, args1) + matchParams(RefinedType(t, tparam.paramName, arg.toBounds), tparams1, args1) } catch { case ex: MatchError => println(s"applied type mismatch: $self with underlying ${self.underlyingIfProxy}, args = $args, typeParams = $typParams") // !!! DEBUG @@ -463,15 +463,10 @@ class TypeApplications(val self: Type) extends AnyVal { appliedTo(args) } - /** Turn this type, which is used as an argument for - * type parameter `tparam`, into a TypeBounds RHS - */ - final def toBounds(tparam: ParamInfo)(implicit ctx: Context): TypeBounds = self match { - case self: TypeBounds => // this can happen for wildcard args - self - case _ => - val v = tparam.paramVariance - TypeAlias(self, v) + /** Turns non-bounds types to type aliases */ + final def toBounds(implicit ctx: Context): TypeBounds = self match { + case self: TypeBounds => self // this can happen for wildcard args + case _ => TypeAlias(self) } /** The type arguments of this type's base type instance wrt. `base`. diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 51054c96ff96..ffd687f95546 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -525,8 +525,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp2 @ TypeBounds(lo2, hi2) => def compareTypeBounds = tp1 match { case tp1 @ TypeBounds(lo1, hi1) => - (tp2.variance > 0 && tp1.variance >= 0 || (lo2 eq NothingType) || isSubType(lo2, lo1)) && - (tp2.variance < 0 && tp1.variance <= 0 || (hi2 eq AnyType) || isSubType(hi1, hi2)) + ((lo2 eq NothingType) || isSubType(lo2, lo1)) && + ((hi2 eq AnyType) || isSubType(hi1, hi2)) case tp1: ClassInfo => tp2 contains tp1 case _ => @@ -963,8 +963,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tp2.refinedInfo match { case rinfo2: TypeBounds => val ref1 = tp1.widenExpr.select(name) - (rinfo2.variance > 0 || isSubType(rinfo2.lo, ref1)) && - (rinfo2.variance < 0 || isSubType(ref1, rinfo2.hi)) + isSubType(rinfo2.lo, ref1) && isSubType(ref1, rinfo2.hi) case _ => false } @@ -1447,13 +1446,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val rinfo1 = tp1.refinedInfo val rinfo2 = tp2.refinedInfo val parent = tp1.parent & tp2.parent - - def isNonvariantAlias(tp: Type) = tp match { - case tp: TypeAlias => tp.variance == 0 - case _ => false - } - if (homogenizeArgs && - isNonvariantAlias(rinfo1) && isNonvariantAlias(rinfo2)) + if (homogenizeArgs && rinfo1.isAlias && rinfo2.isAlias) // @!!! probably drop this case? isSameType(rinfo1, rinfo2) // establish new constraint tp1.derivedRefinedType(parent, tp1.refinedName, rinfo1 & rinfo2) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index eec1d093d4a7..3ca8f1020cb6 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. tp case tp: RefinedType => //@!!! derivedRefinedType(tp, apply(tp.parent), apply(tp.refinedInfo)) - case tp: TypeAlias if tp.variance == 1 => // if variance != 1, need to do the variance calculation - derivedTypeAlias(tp, apply(tp.alias)) case _ => mapOver(tp) } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bdaf4478b144..8829c6ed8d8c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3557,23 +3557,13 @@ object Types { assert(lo.isInstanceOf[TermType]) assert(hi.isInstanceOf[TermType]) - def variance: Int = 0 - override def underlying(implicit ctx: Context): Type = hi /** The non-alias type bounds type with given bounds */ def derivedTypeBounds(lo: Type, hi: Type)(implicit ctx: Context) = - if ((lo eq this.lo) && (hi eq this.hi) && (variance == 0)) this + if ((lo eq this.lo) && (hi eq this.hi)) this else TypeBounds(lo, hi) - /** If this is an alias, a derived alias with the new variance, - * Otherwise the type itself. - */ - def withVariance(variance: Int)(implicit ctx: Context) = this match { - case tp: TypeAlias => tp.derivedTypeAlias(tp.alias, variance) - case _ => this - } - def contains(tp: Type)(implicit ctx: Context): Boolean = tp match { case tp: TypeBounds => lo <:< tp.lo && tp.hi <:< hi case tp: ClassInfo => @@ -3603,58 +3593,31 @@ object Types { case _ => super.| (that) } - /** The implied bounds, where aliases are mapped to intervals from - * Nothing/Any - */ - def boundsInterval(implicit ctx: Context): TypeBounds = this - - /** If this type and that type have the same variance, this variance, otherwise 0 */ - final def commonVariance(that: TypeBounds): Int = (this.variance + that.variance) / 2 + override def computeHash = doHash(lo, hi) - override def computeHash = doHash(variance, lo, hi) + // @!!! we are not systematic when we do referntial vs structural comparisons. + // Do referential everywhere? override def equals(that: Any): Boolean = that match { case that: TypeBounds => - (this.lo eq that.lo) && (this.hi eq that.hi) && (this.variance == that.variance) + (this.lo eq that.lo) && (this.hi eq that.hi) case _ => false } - - override def toString = - if (lo eq hi) s"TypeAlias($lo, $variance)" else s"TypeBounds($lo, $hi)" } class RealTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) // @!!! get rid of variance - abstract class TypeAlias(val alias: Type, override val variance: Int) extends TypeBounds(alias, alias) { - /** pre: this is a type alias */ - def derivedTypeAlias(alias: Type, variance: Int = this.variance)(implicit ctx: Context) = - if ((alias eq this.alias) && (variance == this.variance)) this - else TypeAlias(alias, variance) - - override def & (that: TypeBounds)(implicit ctx: Context): TypeBounds = { - val v = this commonVariance that - if (v > 0) derivedTypeAlias(this.hi & that.hi, v) - else if (v < 0) derivedTypeAlias(this.lo | that.lo, v) - else super.& (that) - } + abstract class TypeAlias(val alias: Type) extends TypeBounds(alias, alias) { - override def | (that: TypeBounds)(implicit ctx: Context): TypeBounds = { - val v = this commonVariance that - if (v > 0) derivedTypeAlias(this.hi | that.hi, v) - else if (v < 0) derivedTypeAlias(this.lo & that.lo, v) - else super.| (that) - } - - override def boundsInterval(implicit ctx: Context): TypeBounds = - if (variance == 0) this - else if (variance < 0) TypeBounds.lower(alias) - else TypeBounds.upper(alias) + /** pre: this is a type alias */ + def derivedTypeAlias(alias: Type)(implicit ctx: Context) = + if (alias eq this.alias) this else TypeAlias(alias) - override def computeHash = doHash(variance, alias) + override def computeHash = doHash(alias) } - class CachedTypeAlias(alias: Type, variance: Int) extends TypeAlias(alias, variance) + class CachedTypeAlias(alias: Type) extends TypeAlias(alias) object TypeBounds { def apply(lo: Type, hi: Type)(implicit ctx: Context): TypeBounds = @@ -3665,8 +3628,8 @@ object Types { } object TypeAlias { - def apply(alias: Type, variance: Int = 0)(implicit ctx: Context) = - unique(new CachedTypeAlias(alias, variance)) + def apply(alias: Type)(implicit ctx: Context) = + unique(new CachedTypeAlias(alias)) def unapply(tp: TypeAlias): Option[Type] = Some(tp.alias) } @@ -3915,7 +3878,7 @@ object Types { derivedRefinedType(tp, this(tp.parent), this(tp.refinedInfo)) case tp: TypeAlias => - derivedTypeAlias(tp, atVariance(variance * tp.variance)(this(tp.alias))) + derivedTypeAlias(tp, atVariance(0)(this(tp.alias))) case tp: TypeBounds => variance = -variance @@ -4108,22 +4071,12 @@ object Types { else info match { case Range(infoLo: TypeBounds, infoHi: TypeBounds) => assert(variance == 0) - val v1 = infoLo.variance - val v2 = infoHi.variance - // There's some weirdness coming from the way aliases can have variance - // If infoLo and infoHi are both aliases with the same non-zero variance - // we can propagate to a range of the refined types. If they are both - // non-alias ranges we know that infoLo <:< infoHi and therefore we can - // propagate to refined types with infoLo and infoHi as bounds. - // In all other cases, Nothing..Any is the only interval that contains - // the range. i966.scala is a test case. - if (v1 > 0 && v2 > 0) propagate(infoLo, infoHi) - else if (v1 < 0 && v2 < 0) propagate(infoHi, infoLo) - else if (!infoLo.isAlias && !infoHi.isAlias) propagate(infoLo, infoHi) + if (!infoLo.isAlias && !infoHi.isAlias) propagate(infoLo, infoHi) else range(tp.bottomType, tp.topType) // Using `parent` instead of `tp.topType` would be better for normal refinements, // but it would also turn *-types into hk-types, which is not what we want. // We should revisit this point in case we represent applied types not as refinements anymore. + // @!!! revisit case Range(infoLo, infoHi) => propagate(infoLo, infoHi) case _ => @@ -4303,7 +4256,7 @@ object Types { this(this(x, tp.parent), tp.refinedInfo) case bounds @ TypeBounds(lo, hi) => - if (lo eq hi) atVariance(variance * bounds.variance)(this(x, lo)) + if (lo eq hi) atVariance(0)(this(x, lo)) else { variance = -variance val y = this(x, lo) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 6b57caaab057..e1547a958a59 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -153,11 +153,11 @@ Standard-Section: "ASTs" TopLevelStat* TYPEREFpkg fullyQualified_NameRef TYPEREF possiblySigned_NameRef qual_Type RECtype parent_Type + TYPEALIAS alias_Type SUPERtype Length this_Type underlying_Type REFINEDtype Length underlying_Type refinement_NameRef info_Type APPLIEDtype Length tycon_Type arg_Type* TYPEBOUNDS Length low_Type high_Type - TYPEALIAS Length alias_Type (COVARIANT | CONTRAVARIANT)? ANNOTATEDtype Length underlying_Type fullAnnotation_Term ANDtype Length left_Type right_Type ORtype Length left_Type right_Type @@ -322,7 +322,8 @@ object TastyFormat { final val PRIVATEqualified = 104 final val PROTECTEDqualified = 105 final val RECtype = 106 - final val SINGLETONtpt = 107 + final val TYPEALIAS = 107 + final val SINGLETONtpt = 108 final val IDENT = 112 final val IDENTtpt = 113 @@ -370,7 +371,6 @@ object TastyFormat { final val APPLIEDtpt = 162 final val TYPEBOUNDS = 163 final val TYPEBOUNDStpt = 164 - final val TYPEALIAS = 165 final val ANDtype = 166 final val ANDtpt = 167 final val ORtype = 168 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 43756ddfa3fa..016f26436fc7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -220,14 +220,7 @@ class TreePickler(pickler: TastyPickler) { pickleType(tpe.parent) case tpe: TypeAlias => writeByte(TYPEALIAS) - withLength { - pickleType(tpe.alias, richTypes) - tpe.variance match { - case 1 => writeByte(COVARIANT) - case -1 => writeByte(CONTRAVARIANT) - case 0 => - } - } + pickleType(tpe.alias, richTypes) case tpe: TypeBounds => writeByte(TYPEBOUNDS) withLength { pickleType(tpe.lo, richTypes); pickleType(tpe.hi, richTypes) } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index f287edc4e821..d25d33c949cb 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -232,13 +232,6 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi readType().appliedTo(until(end)(readType())) case TYPEBOUNDS => TypeBounds(readType(), readType()) - case TYPEALIAS => - val alias = readType() - val variance = - if (nextByte == COVARIANT) { readByte(); 1 } - else if (nextByte == CONTRAVARIANT) { readByte(); -1 } - else 0 - TypeAlias(alias, variance) case ANNOTATEDtype => AnnotatedType(readType(), Annotation(readTerm())) case ANDtype => @@ -296,6 +289,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi RecType(rt => registeringType(rt, readType())) case RECthis => readTypeRef().asInstanceOf[RecType].recThis + case TYPEALIAS => + TypeAlias(readType()) case SHARED => val ref = readAddr() typeAtAddr.getOrElseUpdate(ref, forkAt(ref).readType()) @@ -680,7 +675,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi sym.info = NoCompleter sym.info = rhs.tpe match { case _: TypeBounds | _: ClassInfo => checkNonCyclic(sym, rhs.tpe, reportErrors = false) - case _ => TypeAlias(rhs.tpe, sym.variance) + case _ => TypeAlias(rhs.tpe) } TypeDef(rhs) } diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 602b095fe43e..dfcdab4d40e3 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -314,11 +314,7 @@ class PlainPrinter(_ctx: Context) extends Printer { protected def toTextRHS(tp: Type): Text = controlled { homogenize(tp) match { case tp: TypeAlias => - val eql = - if (tp.variance == 1) " =+ " - else if (tp.variance == -1) " =- " - else " = " - eql ~ toText(tp.alias) + " = " ~ toText(tp.alias) case tp @ TypeBounds(lo, hi) => (if (lo isRef defn.NothingClass) Text() else " >: " ~ toText(lo)) ~ (if (hi isRef defn.AnyClass) Text() else " <: " ~ toText(hi)) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index c0eea50822b6..c2ae261f4b36 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -379,7 +379,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder val name = "_" val ref = new api.ParameterRef(name) new api.Existential(ref, - Array(apiTypeParameter(name, arg.variance, lo, hi))) + Array(apiTypeParameter(name, 0, lo, hi))) } case _ => apiType(arg) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 384b57b85198..ba9d3f17ebdd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1189,10 +1189,7 @@ class Namer { typer: Typer => } val rhsBodyType = typedAheadType(rhs).tpe val rhsType = if (isDerived) rhsBodyType else abstracted(rhsBodyType) - val unsafeInfo = rhsType match { - case bounds: TypeBounds => bounds - case alias => TypeAlias(alias, if (sym is Local) sym.variance else 0) - } + val unsafeInfo = rhsType.toBounds if (isDerived) sym.info = unsafeInfo else { sym.info = NoCompleter diff --git a/compiler/src/dotty/tools/dotc/typer/Variances.scala b/compiler/src/dotty/tools/dotc/typer/Variances.scala index d9519ce51786..2635f9c26434 100644 --- a/compiler/src/dotty/tools/dotc/typer/Variances.scala +++ b/compiler/src/dotty/tools/dotc/typer/Variances.scala @@ -73,7 +73,7 @@ object Variances { case tp @ TypeRef(pre, _) => if (tp.symbol == tparam) Covariant else varianceInType(pre)(tparam) case tp @ TypeBounds(lo, hi) => - if (lo eq hi) compose(varianceInType(hi)(tparam), tp.variance) + if (lo eq hi) cut(varianceInType(hi)(tparam)) else flip(varianceInType(lo)(tparam)) & varianceInType(hi)(tparam) case tp @ RefinedType(parent, _, rinfo) => varianceInType(parent)(tparam) & varianceInType(rinfo)(tparam) diff --git a/tests/pos/Patterns.scala b/tests/pos/Patterns.scala index fd0d7e97ace4..ecbde54df0b0 100644 --- a/tests/pos/Patterns.scala +++ b/tests/pos/Patterns.scala @@ -12,8 +12,7 @@ object Patterns { } } d match { - case WildcardType(bounds: TypeBounds) => - bounds.variance + case WildcardType(bounds: TypeBounds) => bounds.lo case a @ Assign(Ident(id), rhs) => id case a: Object => a } From f4d0942907fe34735521e21ed4141b806017f1a9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 00:38:52 +0200 Subject: [PATCH 084/146] Fix equals for TypeAlias --- compiler/src/dotty/tools/dotc/core/Types.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8829c6ed8d8c..793f98f628ef 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3598,6 +3598,8 @@ object Types { // @!!! we are not systematic when we do referntial vs structural comparisons. // Do referential everywhere? override def equals(that: Any): Boolean = that match { + case that: TypeAlias => + false case that: TypeBounds => (this.lo eq that.lo) && (this.hi eq that.hi) case _ => @@ -3615,6 +3617,13 @@ object Types { if (alias eq this.alias) this else TypeAlias(alias) override def computeHash = doHash(alias) + + override def equals(that: Any): Boolean = that match { + case that: TypeAlias => + this.alias eq that.alias + case _ => + false + } } class CachedTypeAlias(alias: Type) extends TypeAlias(alias) From b665f13de439575fe7429565564c0a333ab9db73 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 09:38:28 +0200 Subject: [PATCH 085/146] Adapt homogenizeArgs to new scheme Todo: We should find out whether it's worth it. --- .../src/dotty/tools/dotc/config/Config.scala | 6 ++-- .../dotty/tools/dotc/core/TypeComparer.scala | 34 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Config.scala b/compiler/src/dotty/tools/dotc/config/Config.scala index fe4de40ec038..d7980b55f36a 100644 --- a/compiler/src/dotty/tools/dotc/config/Config.scala +++ b/compiler/src/dotty/tools/dotc/config/Config.scala @@ -84,12 +84,12 @@ object Config { /** If this flag is set, take the fast path when comparing same-named type-aliases and types */ final val fastPathForRefinedSubtype = true - /** If this flag is set, and we compute `T1 { X = S1 }` & `T2 { X = S2 }` as a new - * upper bound of a constrained parameter, try to align the refinements by computing + /** If this flag is set, and we compute `T1[X1]` & `T2[X2]` as a new + * upper bound of a constrained parameter, try to align the arguments by computing * `S1 =:= S2` (which might instantiate type parameters). * This rule is contentious because it cuts the constraint set. * - * For more info, see the comment in `TypeComparer#distributeAnd`. + * For more info, see the comment in `TypeComparer#glbArgs`. */ final val alignArgsInAnd = true diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index ffd687f95546..cb13b9fdb330 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -1260,6 +1260,20 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { Nil } + /** Try to produce joint arguments for a glb `A[T_1, ..., T_n] & A[T_1', ..., T_n']` using + * the following strategies: + * + * - if corresponding parameter variance is co/contra-variant, the glb/lub. + * - if arguments are the same, that argument. + * - if at least one of the arguments if a TypeBounds, the union of + * the bounds. + * - if homogenizeArgs is set, and arguments can be unified by instantiating + * type parameters, the unified argument. + * - otherwise NoType + * + * The unification rule is contentious because it cuts the constraint set. + * Therefore it is subject to Config option `alignArgsInAnd`. + */ def glbArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo]): List[Type] = tparams match { case tparam :: tparamsRest => @@ -1273,6 +1287,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { else if (arg1.isInstanceOf[TypeBounds] || arg2.isInstanceOf[TypeBounds]) TypeBounds(lub(arg1.loBound, arg2.loBound), glb(arg1.hiBound, arg2.hiBound)) + else if (homogenizeArgs && !frozenConstraint && isSameType(arg1, arg2)) arg1 else NoType glbArg :: glbArgs(args1Rest, args2Rest, tparamsRest) case nil => @@ -1430,26 +1445,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { // opportunistically merge same-named refinements // this does not change anything semantically (i.e. merging or not merging // gives =:= types), but it keeps the type smaller. - // @!!! still needed? case tp1: RefinedType => tp2 match { case tp2: RefinedType if tp1.refinedName == tp2.refinedName => - // Given two refinements `T1 { X = S1 }` and `T2 { X = S2 }` rewrite to - // `T1 & T2 { X B }` where `B` is the conjunction of the bounds of `X` in `T1` and `T2`. - // - // However, if `homogenizeArgs` is set, and both aliases `X = Si` are - // nonvariant, and `S1 =:= S2` (possibly by instantiating type parameters), - // rewrite instead to `T1 & T2 { X = S1 }`. This rule is contentious because - // it cuts the constraint set. On the other hand, without it we would replace - // the two aliases by `T { X >: S1 | S2 <: S1 & S2 }`, which looks weird - // and is probably not what's intended. - val rinfo1 = tp1.refinedInfo - val rinfo2 = tp2.refinedInfo - val parent = tp1.parent & tp2.parent - if (homogenizeArgs && rinfo1.isAlias && rinfo2.isAlias) // @!!! probably drop this case? - isSameType(rinfo1, rinfo2) // establish new constraint - - tp1.derivedRefinedType(parent, tp1.refinedName, rinfo1 & rinfo2) + tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, + tp1.refinedInfo & tp2.refinedInfo) case _ => NoType } From e3c3dda536046c1b9a861f2f9b7a97346a47e9d5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 09:44:51 +0200 Subject: [PATCH 086/146] Drop AnyAppliedType --- .../tools/dotc/core/TypeApplications.scala | 45 ++----------------- .../dotty/tools/dotc/core/TypeComparer.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 2 +- .../tools/dotc/core/tasty/TreePickler.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 5 +-- .../tools/dotc/printing/RefinedPrinter.scala | 2 +- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 1 - .../tools/dottydoc/model/factories.scala | 2 +- 9 files changed, 12 insertions(+), 51 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 2329fad9e995..2d681464c29d 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -64,48 +64,11 @@ object TypeApplications { } def unapply(tp: Type)(implicit ctx: Context): Option[TypeRef] = tp match { - case tp @ HKTypeLambda(tparams, AnyAppliedType(fn: TypeRef, args)) if (args == tparams.map(_.paramRef)) => Some(fn) + case tp @ HKTypeLambda(tparams, AppliedType(fn: TypeRef, args)) if (args == tparams.map(_.paramRef)) => Some(fn) case _ => None } } - /** Extractor for type application T[U_1, ..., U_n]. This is the refined type - * - * T { type p_1 v_1= U_1; ...; type p_n v_n= U_n } - * - * where v_i, p_i are the variances and names of the type parameters of T. - */ - object AnyAppliedType { // @!!! drop - 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 { - case tp: RefinedType => - var refinements: List[RefinedType] = Nil - var tycon = tp.stripTypeVar - while (tycon.isInstanceOf[RefinedType]) { - val rt = tycon.asInstanceOf[RefinedType] - refinements = rt :: refinements - tycon = rt.parent.stripTypeVar - } - def collectArgs(tparams: List[TypeParamInfo], - refinements: List[RefinedType], - argBuf: mutable.ListBuffer[Type]): Option[(Type, List[Type])] = refinements match { - case Nil if tparams.isEmpty && argBuf.nonEmpty => - Some((tycon, argBuf.toList)) - case RefinedType(_, rname, rinfo) :: refinements1 - if tparams.nonEmpty && rname == tparams.head.paramName => - collectArgs(tparams.tail, refinements1, argBuf += rinfo.argInfo) - case _ => - None - } - collectArgs(tycon.typeParams, refinements, new mutable.ListBuffer[Type]) - case AppliedType(tycon, args) => - Some((tycon, args)) - case _ => - None - } - } - /** Adapt all arguments to possible higher-kinded type parameters using etaExpandIfHK */ def EtaExpandIfHK(tparams: List[TypeParamInfo], args: List[Type])(implicit ctx: Context): List[Type] = @@ -400,7 +363,7 @@ class TypeApplications(val self: Type) extends AnyVal { if (!args.exists(_.isInstanceOf[TypeBounds])) { val followAlias = Config.simplifyApplications && { dealiased.resType match { - case AnyAppliedType(tyconBody, dealiasedArgs) => + case AppliedType(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 @@ -413,7 +376,7 @@ class TypeApplications(val self: Type) extends AnyVal { else AppliedType(self, args) } else dealiased.resType match { - case AnyAppliedType(tycon, args1) if tycon.safeDealias ne tycon => + case AppliedType(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 @@ -504,7 +467,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 AnyAppliedType(tycon, args) => args + case AppliedType(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 cb13b9fdb330..b94ab60eee33 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -790,7 +790,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { tycon1 match { case param1: TypeParamRef => def canInstantiate = tp2 match { - case AnyAppliedType(tycon2, args2) => + case AppliedType(tycon2, args2) => tryInstantiate(param1, tycon2.ensureHK) && isSubArgs(args1, args2, tp1, tycon2.typeParams) case _ => false diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 793f98f628ef..e44b7ad665a2 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -150,7 +150,7 @@ object Types { } def isInfixType(implicit ctx: Context): Boolean = this match { - case TypeApplications.AnyAppliedType(tycon, args) => + case AppliedType(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 diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 016f26436fc7..9ba8fcecbe91 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 AnyAppliedType(tycon, args) => + case AppliedType(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 dfcdab4d40e3..6defecb8be50 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -4,7 +4,6 @@ package printing import core._ import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Constants._, Denotations._ import Contexts.Context, Scopes.Scope, Denotations.Denotation, Annotations.Annotation -import TypeApplications.AnyAppliedType import StdNames.{nme, tpnme} import ast.Trees._, ast._ import typer.Implicits._ @@ -133,7 +132,7 @@ class PlainPrinter(_ctx: Context) extends Printer { */ private def refinementChain(tp: Type): List[Type] = tp :: (tp match { - case AnyAppliedType(_, _) => Nil // @!!! + case AppliedType(_, _) => Nil // @!!! case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) case _ => Nil }) @@ -152,7 +151,7 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" case tp: TypeRef => toTextPrefix(tp.prefix) ~ selectionString(tp) - case AnyAppliedType(tycon, args) => + case AppliedType(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 6e880d19d0b4..830de521d863 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -141,7 +141,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { homogenize(tp) match { case x: ConstantType if homogenizedView => return toText(x.widen) - case AnyAppliedType(tycon, args) => + case AppliedType(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 c2ae261f4b36..3755cfad9e46 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.AnyAppliedType(tycon, args) => + case AppliedType(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/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index b5c3e3fb5556..3025f4ac10a2 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -6,7 +6,6 @@ import core._ import ast._ import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._ import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._ -import TypeApplications.AnyAppliedType import util.Positions._ import config.Printers.typr import ast.Trees._ diff --git a/doc-tool/src/dotty/tools/dottydoc/model/factories.scala b/doc-tool/src/dotty/tools/dottydoc/model/factories.scala index 8ad26b5cc8ef..4208fd7608f2 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 AnyAppliedType(tycon, args) => { + case AppliedType(tycon, args) => { val cls = tycon.typeSymbol if (defn.isFunctionClass(cls)) From 80ce8d2672e916b7f75224d1cbd510bd46e95efa Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 09:48:57 +0200 Subject: [PATCH 087/146] Fix printing of infix types - move isInfixType back to RefinedPrinter. Types is already large enough and this is exclusively about printing. - perform argText adaptation of InfixType arguments. --- compiler/src/dotty/tools/dotc/core/Types.scala | 8 -------- .../dotty/tools/dotc/printing/RefinedPrinter.scala | 14 +++++++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e44b7ad665a2..890665bdbf45 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -149,14 +149,6 @@ object Types { false } - def isInfixType(implicit ctx: Context): Boolean = this match { - case AppliedType(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 - case _ => false - } - /** Does this type refer exactly to class symbol `sym`, instead of to a subclass of `sym`? * Implemented like `isRef`, but follows more types: all type proxies as well as and- and or-types */ diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 830de521d863..eee83fbb2d1a 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -125,6 +125,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { ("implicit " provided isImplicit) ~ argStr ~ " => " ~ argText(args.last) } + def isInfixType(tp: Type): Boolean = tp match { + case AppliedType(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 + case _ => false + } + def toTextInfixType(op: Type, args: List[Type]): Text = { /* SLS 3.2.8: all infix types have the same precedence. * In A op B op' C, op and op' need the same associativity. @@ -132,8 +140,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { * needs to be parenthesized if it's an infix type, and vice versa. */ val l :: r :: Nil = args val isRightAssoc = op.typeSymbol.name.endsWith(":") - val leftArg = if (isRightAssoc && l.isInfixType) "(" ~ toText(l) ~ ")" else toText(l) - val rightArg = if (!isRightAssoc && r.isInfixType) "(" ~ toText(r) ~ ")" else toText(r) + val leftArg = if (isRightAssoc && isInfixType(l)) "(" ~ argText(l) ~ ")" else argText(l) + val rightArg = if (!isRightAssoc && isInfixType(r)) "(" ~ argText(r) ~ ")" else argText(r) leftArg ~ " " ~ toTextLocal(op) ~ " " ~ rightArg } @@ -146,7 +154,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tycon.isRepeatedParam) return toTextLocal(args.head) ~ "*" if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction) if (defn.isTupleClass(cls)) return toTextTuple(args) - if (tp.isInfixType) return toTextInfixType(tycon, args) + if (isInfixType(tp)) return toTextInfixType(tycon, args) case EtaExpansion(tycon) => return toText(tycon) case tp: TypeRef => From 7de2c12728c6ed5ba1d51d768db577772b66dcb7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 13:23:38 +0200 Subject: [PATCH 088/146] Drop TypeParamAccessor ... and all code related to it. --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 4 ++-- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/core/Flags.scala | 13 ++++--------- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../dotty/tools/dotc/transform/HoistSuperArgs.scala | 4 ++-- .../src/dotty/tools/dotc/transform/SymUtils.scala | 8 ++++++-- .../tools/dotc/transform/SyntheticMethods.scala | 6 ++---- .../dotty/tools/dotc/transform/ValueClasses.scala | 2 +- .../src/dotty/tools/dotc/typer/TypeAssigner.scala | 6 ++---- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 11 files changed, 23 insertions(+), 28 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index eded1a5b7693..d1dc727428a2 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -5,7 +5,7 @@ package ast import core._ import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ -import Decorators._ +import Decorators._, transform.SymUtils._ import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import language.higherKinds import typer.FrontEnd @@ -70,7 +70,7 @@ object desugar { def apply(tp: Type) = tp match { case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) => val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next() - var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol + var local = defctx.denotNamed(tp.name).suchThat(_.isParamOrAccessor).symbol if (local.exists) (defctx.owner.thisType select local).dealias else { def msg = diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index c8cb259a243e..ba82b72a8720 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -304,7 +304,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { true case pre: ThisType => pre.cls.isStaticOwner || - tp.symbol.is(ParamOrAccessor) && !pre.cls.is(Trait) && ctx.owner.enclosingClass == pre.cls + tp.symbol.isParamOrAccessor && !pre.cls.is(Trait) && ctx.owner.enclosingClass == pre.cls // was ctx.owner.enclosingClass.derivesFrom(pre.cls) which was not tight enough // and was spuriously triggered in case inner class would inherit from outer one // eg anonymous TypeMap inside TypeMap.andThen diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index f256a8be4967..f551b4e54a43 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -249,9 +249,7 @@ object Flags { /** A field generated for a primary constructor parameter (no matter if it's a 'val' or not), * or an accessor of such a field. */ - final val ParamAccessor = commonFlag(14, "") - final val TermParamAccessor = ParamAccessor.toTermFlags - final val TypeParamAccessor = ParamAccessor.toTypeFlags // @!!! + final val ParamAccessor = termFlag(14, "") /** A value or class implementing a module */ final val Module = commonFlag(15, "module") @@ -451,7 +449,7 @@ object Flags { /** Flags guaranteed to be set upon symbol creation */ final val FromStartFlags = - Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor | + Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor.toCommonFlags | Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg | Fresh | Erroneous | ImplicitCommon | Permanent | Synthetic | @@ -557,8 +555,8 @@ object Flags { /** An inline parameter */ final val InlineParam = allOf(Inline, Param) - /** A parameter or parameter accessor */ - final val ParamOrAccessor = Param | ParamAccessor + /** A term parameter or parameter accessor */ + final val TermParamOrAccessor = Param | ParamAccessor /** A lazy or deferred value */ final val LazyOrDeferred = Lazy | Deferred @@ -569,9 +567,6 @@ object Flags { /** A synthetic or private definition */ final val SyntheticOrPrivate = Synthetic | Private - /** A type parameter or type parameter accessor */ - final val TypeParamOrAccessor = TypeParam | TypeParamAccessor - /** A deferred member or a parameter accessor (these don't have right hand sides) */ final val DeferredOrParamAccessor = Deferred | ParamAccessor diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 890665bdbf45..48a19b5f6a25 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1171,7 +1171,7 @@ object Types { /** The full parent types, including all type arguments */ def parents(implicit ctx: Context): List[Type] = this match { case tp @ AppliedType(tycon, args) if tycon.typeSymbol.isClass => - tycon.parents.map(_.subst(tycon.typeSymbol.typeParams, args)) // !@@@ cache? + tycon.parents.map(_.subst(tycon.typeSymbol.typeParams, args)) // @!!! cache? case tp: TypeRef => if (tp.info.isInstanceOf[TempClassInfo]) { tp.reloadDenot() diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index d25d33c949cb..00c9e7d210e7 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -367,7 +367,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi private def normalizeFlags(tag: Int, givenFlags: FlagSet, name: Name, isAbsType: Boolean, rhsIsEmpty: Boolean)(implicit ctx: Context): FlagSet = { val lacksDefinition = rhsIsEmpty && - name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || + name.isTermName && !name.isConstructorName && !givenFlags.is(TermParamOrAccessor) || isAbsType var flags = givenFlags if (lacksDefinition && tag != PARAM) flags |= Deferred diff --git a/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala b/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala index 8737c4c9bf49..8a83c19324f8 100644 --- a/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala +++ b/compiler/src/dotty/tools/dotc/transform/HoistSuperArgs.scala @@ -64,7 +64,7 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer { val constr = cdef.symbol lazy val origParams = // The parameters that can be accessed in the supercall if (constr == cls.primaryConstructor) - cls.info.decls.filter(d => d.is(TypeParam) || d.is(TermParamAccessor)) + cls.info.decls.filter(d => d.is(TypeParam) || d.is(ParamAccessor)) else (cdef.tparams ::: cdef.vparamss.flatten).map(_.symbol) @@ -127,7 +127,7 @@ class HoistSuperArgs extends MiniPhaseTransform with IdentityDenotTransformer { def apply(tp: Type) = tp match { case tp: NamedType if (tp.symbol.owner == cls || tp.symbol.owner == constr) && - tp.symbol.is(ParamOrAccessor) => + tp.symbol.isParamOrAccessor => val mappedSym = origToParam(tp.symbol) if (tp.symbol.isType) mappedSym.typeRef else mappedSym.termRef case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 319cb49d2008..500de30c2a8c 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -60,6 +60,10 @@ class SymUtils(val self: Symbol) extends AnyVal { def isSuperAccessor(implicit ctx: Context) = self.name.is(SuperAccessorName) + /** A type or term parameter or a term parameter accessor */ + def isParamOrAccessor(implicit ctx: Context) = + self.is(Param) || self.is(ParamAccessor) + /** If this is a constructor, its owner: otherwise this. */ final def skipConstructor(implicit ctx: Context): Symbol = if (self.isConstructor) self.owner else self @@ -87,8 +91,8 @@ class SymUtils(val self: Symbol) extends AnyVal { def accessorNamed(name: TermName)(implicit ctx: Context): Symbol = self.owner.info.decl(name).suchThat(_ is Accessor).symbol - def termParamAccessors(implicit ctx: Context): List[Symbol] = - self.info.decls.filter(_ is TermParamAccessor).toList + def paramAccessors(implicit ctx: Context): List[Symbol] = + self.info.decls.filter(_ is ParamAccessor).toList def caseAccessors(implicit ctx:Context) = self.info.decls.filter(_ is CaseAccessor).toList diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala index 3faaaa7f1b8e..8e974e930aa4 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMethods.scala @@ -56,10 +56,8 @@ class SyntheticMethods(thisTransformer: DenotTransformer) { def syntheticMethods(clazz: ClassSymbol)(implicit ctx: Context): List[Tree] = { val clazzType = clazz.appliedRef lazy val accessors = - if (isDerivedValueClass(clazz)) - clazz.termParamAccessors - else - clazz.caseAccessors + if (isDerivedValueClass(clazz)) clazz.paramAccessors + else clazz.caseAccessors val symbolsToSynthesize: List[Symbol] = if (clazz.is(Case)) caseSymbols diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala index 00d491486a6c..4642b34c5ced 100644 --- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala +++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala @@ -31,7 +31,7 @@ object ValueClasses { /** The member of a derived value class that unboxes it. */ def valueClassUnbox(d: ClassDenotation)(implicit ctx: Context): Symbol = // (info.decl(nme.unbox)).orElse(...) uncomment once we accept unbox methods - d.classInfo.decls.find(_.is(TermParamAccessor)) + d.classInfo.decls.find(_.is(ParamAccessor)) /** For a value class `d`, this returns the synthetic cast from the underlying type to * ErasedValueType defined in the companion module. This method is added to the module diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 3025f4ac10a2..c7eaa5bc1e6a 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -64,8 +64,8 @@ trait TypeAssigner { def close(tp: Type) = RecType.closeOver(rt => tp.substThis(cls, rt.recThis)) - val refinableDecls = info.decls.filter( - sym => !(sym.is(TypeParamAccessor | Private) || sym.isConstructor)) + def isRefinable(sym: Symbol) = !sym.is(Private) && !sym.isConstructor + val refinableDecls = info.decls.filter(isRefinable) val raw = (parentType /: refinableDecls)(addRefinement) HKTypeLambda.fromParams(cls.typeParams, raw) match { case tl: HKTypeLambda => tl.derivedLambdaType(resType = close(tl.resType)) @@ -208,8 +208,6 @@ trait TypeAssigner { else errorType(ex"$what cannot be accessed as a member of $pre$where.$whyNot", pos) } } - else if (d.symbol is TypeParamAccessor) - ensureAccessible(d.info.bounds.hi, superAccess, pos) else ctx.makePackageObjPrefixExplicit(tpe withDenot d) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index d0cb1d8d896a..c619d5bd4471 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1413,7 +1413,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit .withType(dummy.nonMemberTermRef) checkVariance(impl1) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) - checkRealizableBounds(cls, cdef.namePos) // !@@@ adapt + checkRealizableBounds(cls, cdef.namePos) val cdef1 = assignType(cpy.TypeDef(cdef)(name, impl1), cls) if (ctx.phase.isTyper && cdef1.tpe.derivesFrom(defn.DynamicClass) && !ctx.dynamicsEnabled) { val isRequired = parents1.exists(_.tpe.isRef(defn.DynamicClass)) From 9c28187b9ccb1a3e241f0b80d4e09aa982aa45b6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 10:12:51 +0200 Subject: [PATCH 089/146] Drop BaseTypeArg flag ... and related code --- .../dotty/tools/dotc/config/ScalaSettings.scala | 1 - .../src/dotty/tools/dotc/core/Definitions.scala | 1 - compiler/src/dotty/tools/dotc/core/Flags.scala | 11 +---------- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 15 --------------- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 2 -- .../tools/dotc/printing/RefinedPrinter.scala | 9 +-------- .../src/dotty/tools/dotc/transform/SymUtils.scala | 3 --- .../dotty/tools/dotc/transform/TreeChecker.scala | 2 -- .../src/dotty/tools/dotc/typer/RefChecks.scala | 1 - .../dotty/tools/dotc/typer/VarianceChecker.scala | 2 +- .../test/dotty/tools/dotc/ast/DesugarTests.scala | 2 -- 11 files changed, 3 insertions(+), 46 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 57cb5bc84885..284c31e81025 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -67,7 +67,6 @@ class ScalaSettings extends Settings.SettingGroup { val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of") val YcheckMods = BooleanSetting("-Ycheck-mods", "Check that symbols and their defining trees have modifiers in sync") val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.") - val debugAlias = BooleanSetting("-Ydebug-alias", "Never follow alias when printing types") val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations") val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions") val debugNames = BooleanSetting("-Ydebug-names", "Show internal representation of names") diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5b4f04312208..ca879d95e03b 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -719,7 +719,6 @@ class Definitions { else ArrayType.appliedTo(elem :: Nil) def unapply(tp: Type)(implicit ctx: Context): Option[Type] = tp.dealias match { case AppliedType(at, arg :: Nil) if at isRef ArrayType.symbol => Some(arg) - case at: RefinedType if (at isRef ArrayType.symbol) && at.argInfos.length == 1 => Some(at.argInfos.head) // @!!! case _ => None } } diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index f551b4e54a43..175fe3acc115 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -303,12 +303,6 @@ object Flags { /** A case parameter accessor */ final val CaseAccessor = termFlag(25, "") - /** A binding for a type parameter of a base class or trait. - */ - final val BaseTypeArg = typeFlag(25, "") // @!!! - - final val CaseAccessorOrBaseTypeArg = CaseAccessor.toCommonFlags - /** A super accessor */ final val Scala2SuperAccessor = termFlag(26, "") @@ -451,7 +445,7 @@ object Flags { final val FromStartFlags = Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor.toCommonFlags | Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic | - CovariantOrOuter | ContravariantOrLabel | CaseAccessorOrBaseTypeArg | + CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags | Fresh | Erroneous | ImplicitCommon | Permanent | Synthetic | SuperAccessorOrScala2x | Inline @@ -573,9 +567,6 @@ object Flags { /** value that's final or inline */ final val FinalOrInline = Final | Inline - /** If symbol of a type alias has these flags, prefer the alias */ - final val AliasPreferred = TypeParam | BaseTypeArg - /** A covariant type parameter instance */ final val LocalCovariant = allOf(Local, Covariant) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 3ca8f1020cb6..bed373a10cea 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -233,21 +233,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. } } - private def enterArgBinding(formal: Symbol, info: Type, cls: ClassSymbol, decls: Scope) = { - val lazyInfo = new LazyType { // needed so we do not force `formal`. - def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { - denot setFlag formal.flags & RetainedTypeArgFlags - denot.info = info - } - } - val sym = ctx.newSymbol( - cls, formal.name, - formal.flagsUNSAFE & RetainedTypeArgFlags | BaseTypeArg | Override, - lazyInfo, - coord = cls.coord) - cls.enter(sym, decls) - } - /** An argument bounds violation is a triple consisting of * - the argument tree * - a string "upper" or "lower" indicating which bound is violated diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 9ba8fcecbe91..b49232bf1f8a 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -144,8 +144,6 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleType(tycon); args.foreach(pickleType(_)) } case ConstantType(value) => pickleConstant(value) - case tpe: TypeRef if tpe.info.isAlias && tpe.symbol.isAliasPreferred => - pickleType(tpe.superType) case tpe: WithFixedSym => val sym = tpe.symbol def pickleRef() = diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index eee83fbb2d1a..e380b41256e5 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -158,14 +158,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case EtaExpansion(tycon) => return toText(tycon) case tp: TypeRef => - val hideType = !ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred) - if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) { - tp.info match { - case TypeAlias(alias) => return toText(alias) - case _ => if (tp.prefix.isInstanceOf[ThisType]) return nameString(tp.symbol) - } - } - else if (tp.symbol.isAnonymousClass && !ctx.settings.uniqid.value) + if (tp.symbol.isAnonymousClass && !ctx.settings.uniqid.value) return toText(tp.info) case ExprType(result) => return "=> " ~ toText(result) diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index 500de30c2a8c..4f35c5e614ae 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -55,9 +55,6 @@ class SymUtils(val self: Symbol) extends AnyVal { def isAnyOverride(implicit ctx: Context) = self.is(Override) || self.is(AbsOverride) // careful: AbsOverride is a term only flag. combining with Override would catch only terms. - def isAliasPreferred(implicit ctx: Context) = - self.is(AliasPreferred) || self.name.is(ExpandedName) - def isSuperAccessor(implicit ctx: Context) = self.name.is(SuperAccessorName) /** A type or term parameter or a term parameter accessor */ diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index b3346265a1c3..e99427867883 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -484,8 +484,6 @@ object TreeChecker { assert(definedBinders.get(tp.binder) != null, s"orphan param: ${tp.show}, hash of binder = ${System.identityHashCode(tp.binder)}, tree = ${tree.show}, type = $tp0") case tp: TypeVar => apply(tp.underlying) - case tp: TypeRef if tp.info.isAlias && tp.symbol.isAliasPreferred => - apply(tp.superType) case _ => mapOver(tp) } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index c3a36ac283ca..a55c7ead20d5 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -253,7 +253,6 @@ object RefChecks { def compatibleTypes(memberTp: Type, otherTp: Type): Boolean = try if (member.isType) // intersection of bounds to refined types must be nonempty - member.is(BaseTypeArg) || // @!!! memberTp.bounds.hi.hasSameKindAs(otherTp.bounds.hi) && ((memberTp frozen_<:< otherTp) || !member.owner.derivesFrom(other.owner) && { diff --git a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala index 9b9866b5b03a..7cc81ceafdcf 100644 --- a/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala +++ b/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala @@ -62,7 +62,7 @@ class VarianceChecker()(implicit ctx: Context) { /** Check variance of abstract type `tvar` when referred from `base`. */ private def checkVarianceOfSymbol(tvar: Symbol): Option[VarianceError] = { val relative = relativeVariance(tvar, base) - if (relative == Bivariant || tvar.is(BaseTypeArg)) None + if (relative == Bivariant) None else { val required = compose(relative, this.variance) def tvar_s = s"$tvar (${varianceString(tvar.flags)} ${tvar.showLocated})" diff --git a/compiler/test/dotty/tools/dotc/ast/DesugarTests.scala b/compiler/test/dotty/tools/dotc/ast/DesugarTests.scala index 75c25611f76f..c61773c84015 100644 --- a/compiler/test/dotty/tools/dotc/ast/DesugarTests.scala +++ b/compiler/test/dotty/tools/dotc/ast/DesugarTests.scala @@ -15,8 +15,6 @@ class DesugarTests extends DottyTest { assert( // remaining symbols must be either synthetic: sym.is(Synthetic) || - // or be a type argument from product: - (sym.isType && sym.is(BaseTypeArg)) || // or be a constructor: sym.name == nme.CONSTRUCTOR, s"found: $sym (${sym.flags})" From 476e9523d6836eb0d9b49022637950662a9e6bd3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 11:12:41 +0200 Subject: [PATCH 090/146] Drop withoutArgs --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/ast/untpd.scala | 4 +- .../dotty/tools/dotc/core/Annotations.scala | 2 +- .../tools/dotc/core/TypeApplications.scala | 37 ++++--------------- .../core/unpickleScala2/Scala2Unpickler.scala | 4 +- .../dotty/tools/dotc/typer/RefChecks.scala | 10 ++--- 6 files changed, 16 insertions(+), 43 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index ba82b72a8720..660c4b81de80 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -380,7 +380,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** new C(args), calling given constructor `constr` of C */ def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = { val targs = tp.argTypes - val tycon = tp.withoutArgs(targs) + val tycon = tp.typeConstructor New(tycon) .select(TermRef.withSig(tycon, constr)) .appliedToTypes(targs) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 52a49de47f88..29fcea80dbad 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -296,9 +296,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { (tycon, targs) case TypedSplice(AppliedTypeTree(tycon, targs)) => (TypedSplice(tycon), targs map (TypedSplice(_))) - case TypedSplice(tpt1: Tree) => + case TypedSplice(tpt1: tpd.Tree) => + val tycon = tpt1.tpe.typeConstructor val argTypes = tpt1.tpe.argTypesLo - val tycon = tpt1.tpe.withoutArgs(argTypes) def wrap(tpe: Type) = TypeTree(tpe) withPos tpt.pos (wrap(tycon), argTypes map wrap) case _ => diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 17b1dba722ef..136edfc6b22d 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -103,7 +103,7 @@ object Annotations { private def resolveConstructor(atp: Type, args:List[Tree])(implicit ctx: Context): Tree = { val targs = atp.argTypes - tpd.applyOverloaded(New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true) + tpd.applyOverloaded(New(atp.typeConstructor), nme.CONSTRUCTOR, args, targs, atp, isAnnotConstructor = true) } def applyResolve(atp: Type, args: List[Tree])(implicit ctx: Context): Annotation = { diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 2d681464c29d..e20dfe156f00 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -173,17 +173,17 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ { self match { - case self: ClassInfo => - self.cls.typeParams - case self: HKTypeLambda => - self.typeParams case self: TypeRef => val tsym = self.symbol if (tsym.isClass) tsym.typeParams else if (!tsym.isCompleting) tsym.info.typeParams else Nil + case self: ClassInfo => + self.cls.typeParams + case self: HKTypeLambda => + self.typeParams case self: RefinedType => - self.parent.typeParams.filterNot(_.paramName == self.refinedName) // @!!! + self.parent.typeParams case self: RecType => self.parent.typeParams case _: SingletonType => @@ -432,12 +432,6 @@ class TypeApplications(val self: Type) extends AnyVal { case _ => TypeAlias(self) } - /** The type arguments of this type's base type instance wrt. `base`. - * Wildcard types in arguments are returned as TypeBounds instances. - */ - final def baseArgInfos(base: Symbol)(implicit ctx: Context): List[Type] = // @!!! drop - self.baseType(base).argInfos - /** Translate a type of the form From[T] to To[T], keep other types as they are. * `from` and `to` must be static classes, both with one type parameter, and the same variance. * Do the same for by name types => From[T] and => To[T] @@ -446,9 +440,7 @@ class TypeApplications(val self: Type) extends AnyVal { case self @ ExprType(tp) => self.derivedExprType(tp.translateParameterized(from, to)) case _ => - if (self.derivesFrom(from)) - if (ctx.erasedTypes) to.typeRef // @!!! can be dropped; appliedTo does the right thing anyway - else to.typeRef.appliedTo(self.baseType(from).argInfos) + if (self.derivesFrom(from)) to.typeRef.appliedTo(self.baseType(from).argInfos) else self } @@ -480,21 +472,6 @@ class TypeApplications(val self: Type) extends AnyVal { /** Argument types where existential types in arguments are approximated by their upper bound */ def argTypesHi(implicit ctx: Context) = argInfos.mapConserve(_.hiBound) - /** The core type without any type arguments. - * @param `typeArgs` must be the type arguments of this type. - */ - final def withoutArgs(typeArgs: List[Type]): Type = self match { // @!!! replace with typeConstructor? - case AppliedType(tycon, args) => tycon - case _ => - typeArgs match { - case _ :: typeArgs1 => - val RefinedType(tycon, _, _) = self // @!!! - tycon.withoutArgs(typeArgs1) - case nil => - self - } - } - /** If this is the image of a type argument; recover the type argument, * otherwise NoType. */ @@ -514,6 +491,6 @@ class TypeApplications(val self: Type) extends AnyVal { def elemType(implicit ctx: Context): Type = self match { case defn.ArrayOf(elemtp) => elemtp case JavaArrayType(elemtp) => elemtp - case _ => baseArgInfos(defn.SeqClass).headOption.getOrElse(NoType) + case _ => self.baseType(defn.SeqClass).argInfos.headOption.getOrElse(NoType) } } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 69531b8fd464..b763e0c06ed1 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -62,7 +62,7 @@ object Scala2Unpickler { case tp: MethodType => val lastArg = tp.paramInfos.last assert(lastArg isRef defn.ArrayClass) - val elemtp0 :: Nil = lastArg.baseArgInfos(defn.ArrayClass) + val elemtp0 :: Nil = lastArg.baseType(defn.ArrayClass).argInfos val elemtp = elemtp0 match { case AndType(t1, t2) if t1.typeSymbol.isAbstractType && (t2 isRef defn.ObjectClass) => t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them. @@ -927,7 +927,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // println(atp) val targs = atp.argTypes - tpd.applyOverloaded(tpd.New(atp withoutArgs targs), nme.CONSTRUCTOR, args, targs, atp) + tpd.applyOverloaded(tpd.New(atp.typeConstructor), nme.CONSTRUCTOR, args, targs, atp) } /** Read an annotation and as a side effect store it into diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index a55c7ead20d5..f531371cd214 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -536,19 +536,15 @@ object RefChecks { def subclassMsg(c1: Symbol, c2: Symbol) = s": ${c1.showLocated} is a subclass of ${c2.showLocated}, but method parameter types must match exactly." val addendum = - if (abstractSym == concreteSym) { - val paArgs = pa.argInfos - val pcArgs = pc.argInfos - val paConstr = pa.withoutArgs(paArgs) - val pcConstr = pc.withoutArgs(pcArgs) - (paConstr, pcConstr) match { + if (abstractSym == concreteSym) + (pa.typeConstructor, pc.typeConstructor) match { case (TypeRef(pre1, _), TypeRef(pre2, _)) => if (pre1 =:= pre2) ": their type parameters differ" else ": their prefixes (i.e. enclosing instances) differ" case _ => "" } - } else if (abstractSym isSubClass concreteSym) + else if (abstractSym isSubClass concreteSym) subclassMsg(abstractSym, concreteSym) else if (concreteSym isSubClass abstractSym) subclassMsg(concreteSym, abstractSym) From 77a09c77f8be601a2e34b874972d7dc55370ae2e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 13:08:29 +0200 Subject: [PATCH 091/146] Drop ClassDenotation.appliedRef and ClassInfo.typeRef - keep typeRef in ClassDenotaton, since we need it before info is completed - keep appliedRef in ClassInfo, since it depends on prefix. --- .../tools/dotc/core/SymDenotations.scala | 11 ++--- .../src/dotty/tools/dotc/core/Types.scala | 43 ++++--------------- .../src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- 3 files changed, 13 insertions(+), 43 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f7e8a0605700..2b9ba58ad182 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1412,20 +1412,15 @@ object SymDenotations { else ThisType.raw(TypeRef(pre, symbol.asType)) } */ - private[this] var myAppliedRef: Type = null // @!!!: Use classInfo.appliedRef instead? - private[this] var myTypeRef: TypeRef = null // @!!!: Use classInfo.appliedRef instead? - - override def appliedRef(implicit ctx: Context): Type = { - if (myAppliedRef == null) myAppliedRef = super.appliedRef - if (ctx.erasedTypes) myAppliedRef.typeConstructor - else myAppliedRef - } + private[this] var myTypeRef: TypeRef = null override def typeRef(implicit ctx: Context): TypeRef = { if (myTypeRef == null) myTypeRef = super.typeRef myTypeRef } + override def appliedRef(implicit ctx: Context): Type = classInfo.appliedRef + private def baseData(implicit onBehalf: BaseData, ctx: Context): (List[ClassSymbol], BaseClassSet) = { if (!baseDataCache.isValid) baseDataCache = BaseData.newCache() baseDataCache(this) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 48a19b5f6a25..98630314cfc4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -470,10 +470,8 @@ object Types { final def memberExcluding(name: Name, excluding: FlagSet)(implicit ctx: Context): Denotation = { // We need a valid prefix for `asSeenFrom` val pre = this match { - case tp: ClassInfo => - tp.typeRef // @!!! appliedRef - case _ => - widenIfUnstable + case tp: ClassInfo => tp.appliedRef + case _ => widenIfUnstable } findMember(name, pre, excluding) } @@ -3432,6 +3430,9 @@ object Types { decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { + private var selfTypeCache: Type = null + private var appliedRefCache: Type = null + /** The self type of a class is the conjunction of * - the explicit self type if given (or the info of a given self symbol), and * - the fully applied reference to the class itself. @@ -3439,41 +3440,15 @@ object Types { def selfType(implicit ctx: Context): Type = { if (selfTypeCache == null) selfTypeCache = { - def fullRef = fullyAppliedRef val given = cls.givenSelfType - val raw = - if (!given.exists) fullRef - else if (cls is Module) given - else if (ctx.erasedTypes) fullRef - else AndType(given, fullRef) - raw//.asSeenFrom(prefix, cls.owner) + if (!given.exists) appliedRef + else if (cls is Module) given + else if (ctx.erasedTypes) appliedRef + else AndType(given, appliedRef) } selfTypeCache } - private var selfTypeCache: Type = null - - //private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = - // base.appliedTo(tparams.map(_.typeRef)) - - /** The class type with all type parameters */ - def fullyAppliedRef(implicit ctx: Context): Type = // @!!! eliminate - //if (true) - cls.appliedRef - //else fullyAppliedRef(cls.typeRef, cls.typeParams) - - private var appliedRefCache: Type = null - private var typeRefCache: TypeRef = null - - def typeRef(implicit ctx: Context): TypeRef = { - def clsDenot = if (prefix eq cls.owner.thisType) cls.denot else cls.denot.copySymDenotation(info = this) - if (typeRefCache == null) - typeRefCache = - if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef - else TypeRef(prefix, cls.name, clsDenot) - typeRefCache - } - 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) { diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 3755cfad9e46..0533de0f36f6 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -234,7 +234,7 @@ private class ExtractAPICollector(implicit val ctx: Context) extends ThunkHolder } def linearizedAncestorTypes(info: ClassInfo): List[Type] = { - val ref = info.fullyAppliedRef + val ref = info.appliedRef // Note that the ordering of classes in `baseClasses` is important. info.baseClasses.tail.map(ref.baseType) } From 5dd8846b15006678a79e46ea5be3265b1d5d2565 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 1 Sep 2017 15:54:47 +0200 Subject: [PATCH 092/146] Reorder and clean up erasure and sigName --- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index ddcbe2c0061f..80cc4768ff4b 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -384,16 +384,14 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean case tp: AppliedType => if (tp.tycon.isRef(defn.ArrayClass)) eraseArray(tp) else apply(tp.superType) - case tp: RefinedType => - val parent = tp.parent - if (parent isRef defn.ArrayClass) eraseArray(tp) // @!!! - else this(parent) case _: TermRef | _: ThisType => this(tp.widen) case SuperType(thistpe, supertpe) => SuperType(this(thistpe), this(supertpe)) case ExprType(rt) => defn.FunctionType(0) + case tp: TypeProxy => + this(tp.underlying) case AndType(tp1, tp2) => erasedGlb(this(tp1), this(tp2), isJava) case OrType(tp1, tp2) => @@ -433,8 +431,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean tp case tp: WildcardType if wildcardOK => tp - case tp: TypeProxy => - this(tp.underlying) } private def eraseArray(tp: Type)(implicit ctx: Context) = { @@ -549,8 +545,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean if (inst.exists) sigName(inst) else tpnme.Uninstantiated case tp: TypeProxy => sigName(tp.underlying) - case tp: PolyType => - sigName(tp.resultType) case _: ErrorType | WildcardType => tpnme.WILDCARD case tp: WildcardType => From 636e30ecc96ab446bf827717d506cddf616ffb74 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 2 Sep 2017 11:37:20 +0200 Subject: [PATCH 093/146] More cleanups and removals of now redundant code --- .../tools/dotc/core/SymDenotations.scala | 15 +++------- .../dotty/tools/dotc/core/TypeErasure.scala | 2 -- .../src/dotty/tools/dotc/core/Types.scala | 22 +++----------- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../tools/dotc/printing/PlainPrinter.scala | 3 +- .../tools/dotc/printing/RefinedPrinter.scala | 6 ++-- .../src/dotty/tools/dotc/typer/Checking.scala | 29 +++++++++---------- .../dotty/tools/dotc/typer/RefChecks.scala | 1 - 8 files changed, 25 insertions(+), 55 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 2b9ba58ad182..07e4f0ed0128 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1402,17 +1402,10 @@ object SymDenotations { } private def computeThisType(implicit ctx: Context): Type = - ThisType.raw( - TypeRef(if (this is Package) NoPrefix else owner.thisType, symbol.asType)) -/* else { - val pre = owner.thisType - if (this is Module) - if (isMissing(pre)) TermRef(pre, sourceModule.asTerm) - else TermRef.withSig(pre, name.sourceModuleName, Signature.NotAMethod) - else ThisType.raw(TypeRef(pre, symbol.asType)) - } -*/ - private[this] var myTypeRef: TypeRef = null + ThisType.raw(TypeRef( + if (this is Package) NoPrefix else owner.thisType, symbol.asType)) + + private[this] var myTypeRef: TypeRef = null override def typeRef(implicit ctx: Context): TypeRef = { if (myTypeRef == null) myTypeRef = super.typeRef diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 80cc4768ff4b..18c58ba6b456 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -532,8 +532,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean else tp.superType) case ErasedValueType(_, underlying) => sigName(underlying) - case defn.ArrayOf(elem) => // @!!! - sigName(this(tp)) case JavaArrayType(elem) => sigName(elem) ++ "[]" case tp: TermRef => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 98630314cfc4..9344199c52ea 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -832,10 +832,6 @@ object Types { } } - /** Temporary replacement for baseTypeRef */ - final def baseTypeTycon(base: Symbol)(implicit ctx: Context): Type = // @!!! drop - baseType(base).typeConstructor - def & (that: Type)(implicit ctx: Context): Type = track("&") { ctx.typeComparer.glb(this, that) } @@ -3488,23 +3484,13 @@ object Types { class CachedClassInfo(prefix: Type, cls: ClassSymbol, classParents: List[Type], decls: Scope, selfInfo: DotClass) extends ClassInfo(prefix, cls, classParents, decls, selfInfo) - /** A class for temporary class infos where `parents` are not yet known. */ + /** A class for temporary class infos where `parents` are not yet known */ final class TempClassInfo(prefix: Type, cls: ClassSymbol, decls: Scope, selfInfo: DotClass) extends CachedClassInfo(prefix, cls, Nil, decls, selfInfo) { - /** A list of actions that were because they rely on the class info of `cls` to - * be no longer temporary. These actions will be performed once `cls` gets a real - * ClassInfo. - */ - private var suspensions: List[Context => Unit] = Nil - - def addSuspension(suspension: Context => Unit): Unit = suspensions ::= suspension - - /** Install classinfo with known parents in `denot` and resume all suspensions */ // @!!! elim - def finalize(denot: SymDenotation, parents: List[Type])(implicit ctx: Context) = { - denot.info = derivedClassInfo(classParents = parents) - suspensions.foreach(_(ctx)) - } + /** Install classinfo with known parents in `denot` s */ + def finalize(denot: SymDenotation, parents: List[Type])(implicit ctx: Context) = + denot.info = ClassInfo(prefix, cls, parents, decls, selfInfo) override def derivedClassInfo(prefix: Type)(implicit ctx: Context) = if (prefix eq this.prefix) this diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index b763e0c06ed1..ad2b74d73890 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -97,7 +97,7 @@ object Scala2Unpickler { // `denot.sourceModule.exists` provision i859.scala crashes in the backend. denot.owner.thisType select denot.sourceModule else selfInfo - val tempInfo = new TempClassInfo(denot.owner.thisType, denot.classSymbol, decls, ost) + val tempInfo = new TempClassInfo(denot.owner.thisType, cls, decls, ost) denot.info = tempInfo // first rough info to avoid CyclicReferences val normalizedParents = if (parents.isEmpty) defn.ObjectType :: Nil diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 6defecb8be50..ce8b4240fcac 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -128,11 +128,10 @@ class PlainPrinter(_ctx: Context) extends Printer { } /** The longest sequence of refinement types, starting at given type - * and following parents, but stopping at applied types. + * and following parents. */ private def refinementChain(tp: Type): List[Type] = tp :: (tp match { - case AppliedType(_, _) => Nil // @!!! case tp: RefinedType => refinementChain(tp.parent.stripTypeVar) case _ => Nil }) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index e380b41256e5..b8631fb517a4 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -62,10 +62,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { override def nameString(name: Name): String = if (ctx.settings.debugNames.value) name.debugString else name.toString - override protected def simpleNameString(sym: Symbol): String = { - val name = if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name - nameString(if (sym.is(TypeParam)) name.asTypeName.unexpandedName else name) // @!!! - } + override protected def simpleNameString(sym: Symbol): String = + nameString(if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name) override def fullNameString(sym: Symbol): String = if (isEmptyPrefix(sym.maybeOwner)) nameString(sym) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 248144e6048e..172f89841908 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -487,7 +487,7 @@ object Checking { ctx.error(ValueClassesMayNotWrapItself(clazz), clazz.pos) else { val clParamAccessors = clazz.asClass.paramAccessors.filter { param => - param.isTerm && !param.is(Flags.Accessor) // @!!! + param.isTerm && !param.is(Flags.Accessor) } clParamAccessors match { case param :: params => @@ -569,29 +569,26 @@ trait Checking { * are feasible, i.e. that their lower bound conforms to their upper bound. If a type * argument is infeasible, issue and error and continue with upper bound. */ - def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = + def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = { + def checkGoodBounds(tp: Type) = tp match { + case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => + ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) + TypeBounds(hi, hi) + case _ => + tp + } tp match { case tp @ AndType(tp1, tp2) => ctx.error(s"conflicting type arguments$where", pos) tp1 case tp @ AppliedType(tycon, args) => - def checkArg(arg: Type) = arg match { - case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => - ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) - hi - case _ => arg - } - tp.derivedAppliedType(tycon, args.mapConserve(checkArg)) - case tp: RefinedType => // @!!! - tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasibleParent(tp.refinedInfo, pos, where)) - case tp: RecType => // @!!! - tp.rebind(tp.parent) - case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => // @!!! - ctx.error(ex"no type exists between low bound $lo and high bound $hi$where", pos) - TypeAlias(hi) + tp.derivedAppliedType(tycon, args.mapConserve(checkGoodBounds)) + case tp: RefinedType => + tp.derivedRefinedType(tp.parent, tp.refinedName, checkGoodBounds(tp.refinedInfo)) case _ => tp } + } /** Check that `tree` is a pure expression of constant type */ def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit = diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index f531371cd214..2fe5a0a6f69c 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -85,7 +85,6 @@ object RefChecks { */ private def upwardsThisType(cls: Symbol)(implicit ctx: Context) = cls.info match { case ClassInfo(_, _, _, _, tp: Type) if (tp ne cls.typeRef) && !cls.is(ModuleOrFinal) => - // @!!! case ClassInfo(_, _, _, _, selfTp: Type) if selfTp.exists && !cls.is(ModuleOrFinal) => SkolemType(cls.typeRef).withName(nme.this_) case _ => cls.thisType From 0a5dfe9d8a4bbc42d6a7a52df4ba305c92b02a3e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 2 Sep 2017 17:06:01 +0200 Subject: [PATCH 094/146] Better implementation of mapArgs --- compiler/src/dotty/tools/dotc/core/Types.scala | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9344199c52ea..13050d3e82be 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3452,7 +3452,7 @@ object Types { if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef else TypeRef(prefix, cls.name, clsDenot) appliedRefCache = - tref.appliedTo(cls.typeParams.map(_.typeRef)) // @!!! cache? + tref.appliedTo(cls.typeParams.map(_.typeRef)) } appliedRefCache } @@ -3562,7 +3562,6 @@ object Types { class RealTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) - // @!!! get rid of variance abstract class TypeAlias(val alias: Type) extends TypeBounds(alias, alias) { /** pre: this is a type alias */ @@ -3829,12 +3828,17 @@ object Types { | NoPrefix => tp case tp: AppliedType => - def mapArg(arg: Type, tparam: ParamInfo): Type = arg match { - case arg: TypeBounds => this(arg) - case _ => atVariance(variance * tparam.paramVariance)(this(arg)) + def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match { + case arg :: args1 => + val arg1 = arg match { + case arg: TypeBounds => this(arg) + case arg => atVariance(variance * tparams.head.paramVariance)(this(arg)) + } + arg1 :: mapArgs(args1, tparams.tail) + case nil => + nil } - derivedAppliedType(tp, this(tp.tycon), - tp.args.zipWithConserve(tp.typeParams)(mapArg)) + derivedAppliedType(tp, this(tp.tycon), mapArgs(tp.args, tp.typeParams)) case tp: RefinedType => derivedRefinedType(tp, this(tp.parent), this(tp.refinedInfo)) From 975a29b24ab6c7460650700fbabfc88222c8729f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 3 Sep 2017 12:15:12 +0200 Subject: [PATCH 095/146] Specialize hash-consing of WithFixedSym types --- .../src/dotty/tools/dotc/core/Contexts.scala | 4 +++ .../src/dotty/tools/dotc/core/Types.scala | 14 +++++---- .../src/dotty/tools/dotc/core/Uniques.scala | 30 +++++++++++++++++-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index df330c4da0b5..ea931ba75301 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -614,9 +614,13 @@ object Contexts { /** A table for hash consing unique named types */ private[core] val uniqueNamedTypes = new NamedTypeUniques + /** A table for hash consing unique symbolic named types */ + private[core] val uniqueWithFixedSyms = new WithFixedSymUniques + private def uniqueSets = Map( "uniques" -> uniques, "uniqueAppliedTypes" -> uniqueAppliedTypes, + "uniqueWithFixedSyms" -> uniqueWithFixedSyms, "uniqueNamedTypes" -> uniqueNamedTypes) /** A map that associates label and size of all uniques sets */ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 13050d3e82be..fafa2d9bbec7 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2020,7 +2020,7 @@ object Types { case that: WithFixedSym => this.prefix == that.prefix && (this.fixedSym eq that.fixedSym) case _ => false } - override def computeHash = doHash(fixedSym, prefix) + override def computeHash = unsupported("computeHash") } final class CachedTermRef(prefix: Type, name: TermName, hc: Int) extends TermRef(prefix, name) { @@ -2036,8 +2036,12 @@ object Types { } // Those classes are non final as Linker extends them. - class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym - class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym + class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol, hc: Int) extends TermRef(prefix, name) with WithFixedSym { + myHash = hc + } + class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol, hc: Int) extends TypeRef(prefix, name) with WithFixedSym { + myHash = hc + } /** Assert current phase does not have erasure semantics */ private def assertUnerased()(implicit ctx: Context) = @@ -2094,7 +2098,7 @@ object Types { * with given prefix, name, and signature */ def withFixedSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = - unique(new TermRefWithFixedSym(prefix, name, sym)) + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRef] /** Create a term ref referring to given symbol with given name, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2148,7 +2152,7 @@ object Types { * with given prefix, name, and symbol. */ def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - unique(new TypeRefWithFixedSym(prefix, name, sym)) + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRef] /** Create a type ref referring to given symbol with given name. * This is very similar to TypeRef(Type, Symbol), diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index 6e80f519868a..74b755e22c9a 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._, Contexts._, util.Stats._, Hashable._, Names._ +import Types._, Symbols._, Contexts._, util.Stats._, Hashable._, Names._ import config.Config import util.HashSet @@ -54,7 +54,7 @@ object Uniques { def enterIfNew(prefix: Type, name: Name): NamedType = { val h = doHash(name, prefix) - if (monitored) recordCaching(h, classOf[CachedTermRef]) + if (monitored) recordCaching(h, classOf[NamedType]) def newType = if (name.isTypeName) new CachedTypeRef(prefix, name.asTypeName, h) else new CachedTermRef(prefix, name.asTermName, h) @@ -66,6 +66,32 @@ object Uniques { } } + final class WithFixedSymUniques extends HashSet[WithFixedSym](Config.initialUniquesCapacity) with Hashable { + override def hash(x: WithFixedSym): Int = x.hash + + private def findPrevious(h: Int, prefix: Type, sym: Symbol): NamedType = { + var e = findEntryByHash(h) + while (e != null) { + if ((e.prefix eq prefix) && (e.fixedSym eq sym)) return e + e = nextEntryByHash(h) + } + e + } + + def enterIfNew(prefix: Type, name: Name, sym: Symbol): NamedType = { + val h = doHash(sym, prefix) + if (monitored) recordCaching(h, classOf[WithFixedSym]) + def newType = + if (name.isTypeName) new TypeRefWithFixedSym(prefix, name.asTypeName, sym.asInstanceOf[TypeSymbol], h) + else new TermRefWithFixedSym(prefix, name.asTermName, sym.asInstanceOf[TermSymbol], h) + if (h == NotCached) newType + else { + val r = findPrevious(h, prefix, sym) + if (r ne null) r else addEntryAfterScan(newType) + } + } + } + final class AppliedUniques extends HashSet[AppliedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: AppliedType): Int = x.hash From db28f4983ed9d0758797c79c04141ba6eeae2be9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 4 Sep 2017 08:43:10 +0200 Subject: [PATCH 096/146] Avoid creating unnecessary new lists in mapArgs --- compiler/src/dotty/tools/dotc/core/Types.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index fafa2d9bbec7..f4f52ee44eb4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3833,12 +3833,14 @@ object Types { case tp: AppliedType => def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match { - case arg :: args1 => + case arg :: otherArgs => val arg1 = arg match { case arg: TypeBounds => this(arg) case arg => atVariance(variance * tparams.head.paramVariance)(this(arg)) } - arg1 :: mapArgs(args1, tparams.tail) + val otherArgs1 = mapArgs(otherArgs, tparams.tail) + if ((arg1 eq arg) && (otherArgs1 eq otherArgs)) args + else arg1 :: otherArgs1 case nil => nil } From 7cf463719862a31443eb653c86c7a3149cfe1fd6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 15:11:35 +0200 Subject: [PATCH 097/146] Drop unused RefType and ClassRef --- compiler/src/dotty/tools/dotc/core/Types.scala | 17 ++--------------- .../src/dotty/tools/dotc/typer/Checking.scala | 3 ++- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index f4f52ee44eb4..c0c271864a44 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1458,11 +1458,6 @@ 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). */ @@ -1494,7 +1489,7 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ /** A NamedType of the form Prefix # name */ - abstract class NamedType extends CachedProxyType with RefType { + abstract class NamedType extends CachedProxyType with ValueType { val prefix: Type val name: Name @@ -3079,7 +3074,7 @@ object Types { /** A type application `C[T_1, ..., T_n]` */ abstract case class AppliedType(tycon: Type, args: List[Type]) - extends CachedProxyType with RefType { + extends CachedProxyType with ValueType { private var validSuper: Period = Nowhere private var cachedSuper: Type = _ @@ -3106,8 +3101,6 @@ object Types { cachedSuper } - override def symbol(implicit ctx: Context) = tycon.typeSymbol - def lowerBound(implicit ctx: Context) = tycon.stripTypeVar match { case tycon: TypeRef => tycon.info match { @@ -3142,12 +3135,6 @@ object Types { } } - 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 reference to wildcard argument `p.` * where `p: C[... _ ...]` */ diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 172f89841908..c958c2b80178 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -447,7 +447,8 @@ object Checking { classParents = tp.parents.map { p => apply(p).stripAnnots match { - case ref: RefType => ref + case ref: TypeRef => ref + case ref: AppliedType => ref case _ => defn.ObjectType // can happen if class files are missing } } From eddc4a458e107dcd4cbf50c604c56948032d137f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 15:14:45 +0200 Subject: [PATCH 098/146] Remove unused code --- .../dotty/tools/dotc/core/TypeApplications.scala | 13 ------------- .../tools/dotc/transform/ElimErasedValueType.scala | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index e20dfe156f00..449901579e6a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -341,19 +341,6 @@ class TypeApplications(val self: Type) extends AnyVal { */ final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ { val typParams = self.typeParams - def matchParams(t: Type, tparams: List[ParamInfo], args: List[Type])(implicit ctx: Context): Type = args match { - case arg :: args1 => - try { - val tparam :: tparams1 = tparams - matchParams(RefinedType(t, tparam.paramName, arg.toBounds), tparams1, args1) - } catch { - case ex: MatchError => - println(s"applied type mismatch: $self with underlying ${self.underlyingIfProxy}, args = $args, typeParams = $typParams") // !!! DEBUG - //println(s"precomplete decls = ${self.typeSymbol.unforcedDecls.toList.map(_.denot).mkString("\n ")}") - throw ex - } - case nil => t - } val stripped = self.stripTypeVar val dealiased = stripped.safeDealias if (args.isEmpty || ctx.erasedTypes) self diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 6f091fee2683..913264081207 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -103,8 +103,8 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer { // Maybe we should move mixin forwarding after erasure to avoid redundant forwarders like these. ctx.error( em"""double definition: - |$sym1: $info1 ${sym1.flags} in ${sym1.owner} and - |$sym2: $info2 ${sym2.flags} in ${sym2.owner} + |$sym1: $info1 in ${sym1.owner} and + |$sym2: $info2 in ${sym2.owner} |have same type after erasure: $info""", root.pos) } From 417ca7e66bc546aead7b43a1f715f12455f60717 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 4 Sep 2017 18:13:22 +0200 Subject: [PATCH 099/146] Reverted: Refine Space#refine to handle AppliedTypes #3054 has a better approach. --- .../tools/dotc/transform/patmat/Space.scala | 59 +------------------ 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 4e2f87cebc36..9f14edb71e55 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -557,16 +557,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { * definition! */ def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match { - case (tp1: RefinedType, _: TypeRef) => - val res = tp1.wrapIfMember(refine(tp1.parent, tp2)) - debug.println(i"refine($tp1, $tp2) = $res") - res - case (tp1 @ AppliedType(tycon, args), tp2: TypeRef) - if tp2.symbol.typeParams.nonEmpty && tp2.symbol.derivesFrom(tycon.typeSymbol) => - val tp1a = tp1.derivedAppliedType(refine(tycon, tp2), args) - val res = derivingType(tp1a.asInstanceOf[AppliedType], tp2) - debug.println(i"refine($tp1, $tp2) = $res") - res + case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2)) case (tp1: AppliedType, _) => refine(tp1.superType, tp2) case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) => if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2 @@ -575,54 +566,6 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { case _ => tp2 } -/** This might be useful for adapting to the new applied type scheme: */ - - import TypeApplications._ - import typer.ProtoTypes.constrained - import ast.untpd - - /** If `clsRef` is a subclass of `tp1`, the largest class type of the form - * - * pre.[args] - * - * which is a subtype of `tp1`. - */ - def derivingType(tp1: AppliedType, clsRef: TypeRef): Type = { - val cls = clsRef.symbol - val typeParams = cls.typeParams - if (tp1.tycon.typeSymbol == cls) tp1 - else { - val abstracted = PolyType.fromParams( - cls.typeParams, clsRef.appliedTo(typeParams.map(_.typeRef))).asInstanceOf[PolyType] - val (schema, _) = constrained(abstracted, untpd.EmptyTree) - schema <:< tp1 - val constraint = ctx.typerState.constraint - def avoidParamRefs(seen: Set[TypeParamRef], v: Int): ApproximatingTypeMap = new ApproximatingTypeMap { - variance = if (v >= 0) 1 else -1 - def apply(t: Type) = t match { - case t: TypeParamRef if schema.paramRefs contains t => - val lo = atVariance(-variance)(apply(constraint.fullLowerBound(t))) - val hi = - if (seen.contains(t)) t.topType - else avoidParamRefs(seen + t, variance)(constraint.fullUpperBound(t)) - range(lo, hi) - case _ => mapOver(t) - } - } - val boundss = abstracted.paramRefs.map(constraint.fullBounds) - def boundsToArg(bounds: TypeBounds, tparam: TypeSymbol): Type = { - val v = tparam.paramVariance - val arg = - if (v < 0 || (bounds.hi frozen_<:< bounds.lo)) bounds.lo - else if (v > 0) bounds.hi - else bounds - avoidParamRefs(Set.empty, v)(arg) - } - val args = (boundss, typeParams).zipped.map(boundsToArg) - clsRef.appliedTo(args) - } - } - /** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */ def canDecompose(tp: Type): Boolean = { val dealiasedTp = tp.dealias From 8456b37ee1192abcdad9fe14b19eeb0e55c9880b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 6 Sep 2017 18:42:04 +0200 Subject: [PATCH 100/146] Disable exhaustivity test --- compiler/test/dotty/tools/dotc/CompilationTests.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index c0277730ba8e..97bfa05e910c 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -169,7 +169,8 @@ class CompilationTests extends ParallelTesting { compileFile("../tests/neg/customArgs/noimports.scala", defaultOptions.and("-Yno-imports")) + compileFile("../tests/neg/customArgs/noimports2.scala", defaultOptions.and("-Yno-imports")) + compileFile("../tests/neg/customArgs/overloadsOnAbstractTypes.scala", allowDoubleBindings) + - compileFile("../tests/neg/customArgs/xfatalWarnings.scala", defaultOptions.and("-Xfatal-warnings")) + + // currently compiles without warning. TODO e-enable when exhaustiveness is fixed. + // compileFile("../tests/neg/customArgs/xfatalWarnings.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg/customArgs/pureStatement.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg/customArgs/phantom-overload.scala", allowDoubleBindings) + compileFile("../tests/neg/customArgs/phantom-overload-2.scala", allowDoubleBindings) + From 826f14e57653ece446a8abc4d780a5290015c4e7 Mon Sep 17 00:00:00 2001 From: liu fengyun Date: Fri, 8 Sep 2017 15:07:37 +0200 Subject: [PATCH 101/146] fix #3015: use type inference to type child classes --- .../tools/dotc/transform/patmat/Space.scala | 107 ++++++++++++------ 1 file changed, 74 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 9f14edb71e55..445a33d0f2a6 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -7,16 +7,19 @@ import Types._ import Contexts._ import Flags._ import ast.Trees._ -import ast.tpd +import ast.{tpd, untpd} import Decorators._ import Symbols._ import StdNames._ import NameOps._ import Constants._ -import typer.Applications._ +import typer._ +import Applications._ +import Inferencing._ +import ProtoTypes._ import transform.SymUtils._ import reporting.diagnostic.messages._ -import config.Printers.{ exhaustivity => debug } +import config.Printers.{exhaustivity => debug} /** Space logic for checking exhaustivity and unreachability of pattern matching * @@ -524,20 +527,10 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { case tp => val parts = children.map { sym => if (sym.is(ModuleClass)) - refine(tp, sym.sourceModule.termRef) - else if (sym.isTerm) - refine(tp, sym.termRef) - else if (sym.info.typeParams.length > 0 || tp.isInstanceOf[TypeRef]) - refine(tp, sym.typeRef) + refine(tp, sym.sourceModule) else - sym.typeRef - } filter { tpe => - // Child class may not always be subtype of parent: - // GADT & path-dependent types - val res = tpe <:< expose(tp) - if (!res) debug.println(s"unqualified child ousted: ${tpe.show} !< ${tp.show}") - res - } + refine(tp, sym) + } filter(_.exists) debug.println(s"${tp.show} decomposes to [${parts.map(_.show).mkString(", ")}]") @@ -545,25 +538,71 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } } - /** Refine tp2 based on tp1 + /** Refine child based on parent + * + * In child class definition, we have: + * + * class Child[Ts] extends path.Parent[Us] with Es + * object Child extends path.Parent[Us] with Es + * val child = new path.Parent[Us] with Es // enum values * - * E.g. if `tp1` is `Option[Int]`, `tp2` is `Some`, then return - * `Some[Int]`. + * Given a parent type `parent` and a child symbol `child`, we infer the prefix + * and type parameters for the child: * - * If `tp1` is `path1.A`, `tp2` is `path2.B`, and `path1` is subtype of - * `path2`, then return `path1.B`. + * prefix.child[Vs] <:< parent + * + * where `Vs` are fresh type variables and `prefix` is the symbol prefix with all + * non-module and non-package `ThisType` replaced by fresh type variables. + * + * If the subtyping is true, the instantiated type `p.child[Vs]` is + * returned. Otherwise, `NoType` is returned. * - * (MO) I don't really understand what this does. Let's try to find a precise - * definition! */ - def refine(tp1: Type, tp2: Type): Type = (tp1, tp2) match { - case (tp1: RefinedType, _: TypeRef) => tp1.wrapIfMember(refine(tp1.parent, tp2)) - case (tp1: AppliedType, _) => refine(tp1.superType, tp2) - case (TypeRef(ref1: TypeProxy, _), tp2 @ TypeRef(ref2: TypeProxy, _)) => - if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2 - case (TypeRef(ref1: TypeProxy, _), tp2 @ TermRef(ref2: TypeProxy, _)) => - if (ref1.underlying <:< ref2.underlying) tp2.derivedSelect(ref1) else tp2 - case _ => tp2 + def refine(parent: Type, child: Symbol): Type = { + if (child.isTerm && child.is(Case, butNot = Module)) return child.termRef // enum vals always match + + val childTp = if (child.isTerm) child.termRef else child.typeRef + + val resTp = instantiate(childTp, expose(parent))(ctx.fresh.setNewTyperState) + + if (!resTp.exists) { + debug.println(s"[refine] unqualified child ousted: ${childTp.show} !< ${parent.show}") + NoType + } + else { + debug.println(s"$child instantiated ------> $resTp") + resTp + } + } + + /** Instantiate type `tp1` to be a subtype of `tp2` + * + * Return the instantiated type if type parameters and this type + * in `tp1` can be instantiated such that `tp1 <:< tp2`. + * + * Otherwise, return NoType. + * + */ + def instantiate(tp1: Type, tp2: Type)(implicit ctx: Context): Type = { + // map `ThisType` of `tp1` to a type variable + // precondition: `tp1` should have the shape `path.Child`, thus `ThisType` is always covariant + val thisTypeMap = new TypeMap { + def apply(t: Type): Type = t match { + case t @ ThisType(tref) if !tref.symbol.isStaticOwner && !tref.symbol.is(Module) => + newTypeVar(TypeBounds.upper(mapOver(tref & tref.givenSelfType))) + case _ => + mapOver(t) + } + } + + val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) } + val protoTp1 = thisTypeMap(tp1.appliedTo(tvars)) + + if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.all)) protoTp1 + else { + debug.println(s"$protoTp1 <:< $tp2 = false") + NoType + } } /** Abstract sealed types, or-types, Boolean and Java enums can be decomposed */ @@ -593,13 +632,13 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { * */ def showType(tp: Type): String = { - val enclosingCls = ctx.owner.enclosingClass.asClass.classInfo.symbolicTypeRef + val enclosingCls = ctx.owner.enclosingClass def isOmittable(sym: Symbol) = sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName || ctx.definitions.UnqualifiedOwnerTypes.exists(_.symbol == sym) || sym.showFullName.startsWith("scala.") || - sym == enclosingCls.typeSymbol + sym == enclosingCls || sym == enclosingCls.sourceModule def refinePrefix(tp: Type): String = tp match { case NoPrefix => "" @@ -607,6 +646,8 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { case tp: ThisType => refinePrefix(tp.tref) case tp: RefinedType => refinePrefix(tp.parent) case tp: NamedType => tp.name.show.stripSuffix("$") + case tp: TypeVar => refinePrefix(tp.instanceOpt) + case _ => tp.show } def refine(tp: Type): String = tp match { From 196b008cd7ca016ebc16eeedcee213fee03d39ca Mon Sep 17 00:00:00 2001 From: liu fengyun Date: Fri, 8 Sep 2017 15:09:07 +0200 Subject: [PATCH 102/146] make exhaustivity check work on native apply --- .../tools/dotc/transform/patmat/Space.scala | 180 +++++++++--------- .../dotty/tools/dotc/CompilationTests.scala | 5 +- .../transform/PatmatExhaustivityTest.scala | 2 +- .../patmat/andtype-opentype-interaction.check | 2 +- .../andtype-refinedtype-interaction.check | 10 +- tests/patmat/exhausting.scala | 2 +- tests/patmat/partial-function.check | 1 + 7 files changed, 96 insertions(+), 106 deletions(-) create mode 100644 tests/patmat/partial-function.check diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 445a33d0f2a6..e17b85cbb0f2 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -403,12 +403,23 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { else Prod(pat.tpe.stripAnnots, fun.tpe.widen, fun.symbol, pats.map(project), irrefutable(fun)) case Typed(pat @ UnApply(_, _, _), _) => project(pat) - case Typed(expr, _) => Typ(expr.tpe.stripAnnots, true) + case Typed(expr, _) => Typ(erase(expr.tpe.stripAnnots), true) case _ => debug.println(s"unknown pattern: $pat") Empty } + /* Erase a type binding according to erasure semantics in pattern matching */ + def erase(tp: Type): Type = tp match { + case tp@AppliedType(tycon, args) => erase(tp.superType) + if (tycon.isRef(defn.ArrayClass)) tp.derivedAppliedType(tycon, args.map(erase)) + else tp.derivedAppliedType(tycon, args.map(t => WildcardType(TypeBounds.empty))) + case OrType(tp1, tp2) => + OrType(erase(tp1), erase(tp2)) + case AndType(tp1, tp2) => + AndType(erase(tp1), erase(tp2)) + case _ => tp + } /** Space of the pattern: unapplySeq(a, b, c: _*) */ @@ -416,7 +427,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { if (pats.isEmpty) return Typ(scalaNilType, false) val (items, zero) = if (pats.last.tpe.isRepeatedParam) - (pats.init, Typ(scalaListType.appliedTo(pats.head.tpe.widen), false)) + (pats.init, Typ(scalaListType.appliedTo(pats.last.tpe.argTypes.head), false)) else (pats, Typ(scalaNilType, false)) @@ -428,41 +439,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } } - - /* Erase a type binding according to erasure semantics in pattern matching */ - def erase(tp: Type): Type = { - def doErase(tp: Type): Type = tp match { - case tp: AppliedType => erase(tp.superType) - case tp: RefinedType => erase(tp.parent) - case _ => tp - } - - tp match { - case OrType(tp1, tp2) => - OrType(erase(tp1), erase(tp2)) - case AndType(tp1, tp2) => - AndType(erase(tp1), erase(tp2)) - case _ => - val origin = doErase(tp) - if (origin =:= defn.ArrayType) tp else origin - } - } - /** Is `tp1` a subtype of `tp2`? */ def isSubType(tp1: Type, tp2: Type): Boolean = { - // `erase` is a workaround to make the following code pass the check: - // - // def f(e: Either[Int, String]) = e match { - // case Left(i) => i - // case Right(s) => 0 - // } - // - // The problem is that when decompose `Either[Int, String]`, `Type.wrapIfMember` - // only refines the type member inherited from `Either` -- it's complex to refine - // the type members in `Left` and `Right`. - // - // FIXME: remove this hack - val res = tp1 <:< erase(tp2) + val res = tp1 <:< tp2 debug.println(s"${tp1.show} <:< ${tp2.show} = $res") res } @@ -563,7 +542,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { val childTp = if (child.isTerm) child.termRef else child.typeRef - val resTp = instantiate(childTp, expose(parent))(ctx.fresh.setNewTyperState) + val resTp = instantiate(childTp, parent)(ctx.fresh.setNewTyperState) if (!resTp.exists) { debug.println(s"[refine] unqualified child ousted: ${childTp.show} !< ${parent.show}") @@ -571,7 +550,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } else { debug.println(s"$child instantiated ------> $resTp") - resTp + resTp.dealias } } @@ -588,8 +567,10 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { // precondition: `tp1` should have the shape `path.Child`, thus `ThisType` is always covariant val thisTypeMap = new TypeMap { def apply(t: Type): Type = t match { - case t @ ThisType(tref) if !tref.symbol.isStaticOwner && !tref.symbol.is(Module) => - newTypeVar(TypeBounds.upper(mapOver(tref & tref.givenSelfType))) + case tp @ ThisType(tref) if !tref.symbol.isStaticOwner && !tref.symbol.is(Module) => + // TODO: stackoverflow here + // newTypeVar(TypeBounds.upper(mapOver(tp.underlying))) + newTypeVar(TypeBounds.upper(mapOver(tref & tref.classSymbol.asClass.givenSelfType))) case _ => mapOver(t) } @@ -598,10 +579,34 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) } val protoTp1 = thisTypeMap(tp1.appliedTo(tvars)) - if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.all)) protoTp1 + // replace type parameter references with fresh type vars or bounds + val typeParamMap = new TypeMap { + def apply(t: Type): Type = t match { + + case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] => + // See tests/patmat/gadt.scala tests/patmat/exhausting.scala + val bound = + if (variance == 0) tp.underlying.bounds // non-variant case is not well-founded + else if (variance == 1) TypeBounds.upper(tp) + else TypeBounds.lower(tp) + newTypeVar(bound) + case tp: RefinedType if tp.refinedInfo.isInstanceOf[TypeBounds] => + // Ideally, we would expect type inference to do the job + // Check tests/patmat/t9657.scala + expose(tp) + case _ => + mapOver(t) + } + } + + if (protoTp1 <:< tp2 && isFullyDefined(protoTp1, ForceDegree.noBottom)) protoTp1 else { - debug.println(s"$protoTp1 <:< $tp2 = false") - NoType + val protoTp2 = typeParamMap(tp2) + if (protoTp1 <:< protoTp2 && isFullyDefined(protoTp1 & protoTp2, ForceDegree.noBottom)) protoTp1 + else { + debug.println(s"$protoTp1 <:< $protoTp2 = false") + NoType + } } } @@ -652,6 +657,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { def refine(tp: Type): String = tp match { case tp: RefinedType => refine(tp.parent) + case tp: AppliedType => refine(tp.typeConstructor) case tp: ThisType => refine(tp.tref) case tp: NamedType => val pre = refinePrefix(tp.prefix) @@ -740,64 +746,50 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { } - /** Expose refined type to eliminate reference to type variables - * - * A = B M { type T = A } ~~> M { type T = B } - * - * A <: X :> Y M { type T = A } ~~> M { type T <: X :> Y } + /** Eliminate reference to type parameters in refinements * * A <: X :> Y B <: U :> V M { type T <: A :> B } ~~> M { type T <: X :> V } - * - * A = X B = Y M { type T <: A :> B } ~~> M { type T <: X :> Y } */ - def expose(tp: Type): Type = { - def follow(tp: Type, up: Boolean): Type = tp match { - case tp: TypeProxy => - tp.underlying match { - case TypeBounds(lo, hi) => - follow(if (up) hi else lo, up) - case _ => - tp - } - case OrType(tp1, tp2) => - OrType(follow(tp1, up), follow(tp2, up)) - case AndType(tp1, tp2) => - AndType(follow(tp1, up), follow(tp2, up)) - } + def expose(tp: Type, refineCtx: Boolean = false, up: Boolean = true): Type = tp match { + case tp: AppliedType => + tp.derivedAppliedType(expose(tp.tycon, refineCtx, up), tp.args.map(expose(_, refineCtx, up))) - tp match { - case tp: RefinedType => - tp.refinedInfo match { - case tpa : TypeAlias => - val hi = follow(tpa.alias, true) - val lo = follow(tpa.alias, false) - val refined = if (hi =:= lo) - tpa.derivedTypeAlias(hi) - else - tpa.derivedTypeBounds(lo, hi) - - tp.derivedRefinedType( - expose(tp.parent), - tp.refinedName, - refined - ) - case tpb @ TypeBounds(lo, hi) => - tp.derivedRefinedType( - expose(tp.parent), - tp.refinedName, - tpb.derivedTypeBounds(follow(lo, false), follow(hi, true)) - ) - case _ => - tp.derivedRefinedType( - expose(tp.parent), - tp.refinedName, - tp.refinedInfo - ) - } - case _ => tp - } + case tp: TypeAlias => + val hi = expose(tp.alias, refineCtx, up) + val lo = expose(tp.alias, refineCtx, up) + + if (hi =:= lo) + tp.derivedTypeAlias(hi) + else + tp.derivedTypeBounds(lo, hi) + + case tp @ TypeBounds(lo, hi) => + tp.derivedTypeBounds(expose(lo, refineCtx, false), expose(hi, refineCtx, true)) + + case tp: RefinedType => + tp.derivedRefinedType( + expose(tp.parent), + tp.refinedName, + expose(tp.refinedInfo, true, up) + ) + case tp: TypeProxy if refineCtx => + tp.underlying match { + case TypeBounds(lo, hi) => + expose(if (up) hi else lo, refineCtx, up) + case _ => + tp + } + + case OrType(tp1, tp2) => + OrType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up)) + + case AndType(tp1, tp2) => + AndType(expose(tp1, refineCtx, up), expose(tp2, refineCtx, up)) + + case _ => tp } + def checkExhaustivity(_match: Match): Unit = { val Match(sel, cases) = _match val selTyp = sel.tpe.widen.dealias diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 97bfa05e910c..2863bff4e48d 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -95,7 +95,7 @@ class CompilationTests extends ParallelTesting { compileFile( // succeeds despite -Xfatal-warnings because of -nowarn "../tests/neg/customArgs/xfatalWarnings.scala", - defaultOptions //.and("-nowarn", "-Xfatal-warnings") // !!! TODO: re-enable when exchaustivity is fixed + defaultOptions.and("-nowarn", "-Xfatal-warnings") ) }.checkCompile() @@ -169,8 +169,7 @@ class CompilationTests extends ParallelTesting { compileFile("../tests/neg/customArgs/noimports.scala", defaultOptions.and("-Yno-imports")) + compileFile("../tests/neg/customArgs/noimports2.scala", defaultOptions.and("-Yno-imports")) + compileFile("../tests/neg/customArgs/overloadsOnAbstractTypes.scala", allowDoubleBindings) + - // currently compiles without warning. TODO e-enable when exhaustiveness is fixed. - // compileFile("../tests/neg/customArgs/xfatalWarnings.scala", defaultOptions.and("-Xfatal-warnings")) + + compileFile("../tests/neg/customArgs/xfatalWarnings.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg/customArgs/pureStatement.scala", defaultOptions.and("-Xfatal-warnings")) + compileFile("../tests/neg/customArgs/phantom-overload.scala", allowDoubleBindings) + compileFile("../tests/neg/customArgs/phantom-overload-2.scala", allowDoubleBindings) + diff --git a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala index 8ea37ee2778e..3ae26e4d421e 100644 --- a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala +++ b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala @@ -65,7 +65,7 @@ class PatmatExhaustivityTest { (file, checkContent, actual) } - // @Test // TODO: reenable when exchaustivity is fixed + @Test def patmatExhaustivity: Unit = { val res = Directory(testsDir).list.toList .filter(f => f.extension == "scala" || f.isDirectory) diff --git a/tests/patmat/andtype-opentype-interaction.check b/tests/patmat/andtype-opentype-interaction.check index c8e212e2f2c5..4ef4731d64bd 100644 --- a/tests/patmat/andtype-opentype-interaction.check +++ b/tests/patmat/andtype-opentype-interaction.check @@ -3,4 +3,4 @@ 31: Pattern Match Exhaustivity: _: Trait & OpenClass 35: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenClass 43: Pattern Match Exhaustivity: _: Trait & OpenAbstractClass -47: Pattern Match Exhaustivity: _: Trait & OpenTrait & OpenClassSubclass +47: Pattern Match Exhaustivity: _: Trait & OpenClass & OpenTrait & OpenClassSubclass diff --git a/tests/patmat/andtype-refinedtype-interaction.check b/tests/patmat/andtype-refinedtype-interaction.check index 149a20fd5fb8..2f8687a868e5 100644 --- a/tests/patmat/andtype-refinedtype-interaction.check +++ b/tests/patmat/andtype-refinedtype-interaction.check @@ -2,9 +2,7 @@ 48: Pattern Match Exhaustivity: _: Clazz & (C1 | C2 | T1){x: Int} & (C3 | C4 | T2){x: Int}, _: Trait & (C1 | C2 | T1){x: Int} & (C3 | C4 | T2){x: Int} 54: Pattern Match Exhaustivity: _: Trait & (C1 | C2 | T1){x: Int} & C3{x: Int} 65: Pattern Match Exhaustivity: _: Trait & (C1 | C2){x: Int} & (C3 | SubC1){x: Int} -72: Pattern Match Exhaustivity: _: Trait & (T1 & C1 | T1 & SubC2){x: Int} & - (T2 & C2 | T2 & C3 | T2 & SubC1){x: Int} - & SubSubC1{x: Int} -79: Pattern Match Exhaustivity: _: Trait & (T1 & C1 | T1 & SubC2){x: Int} & - (T2 & C2 | T2 & C3 | T2 & SubC1){x: Int} - & SubSubC2{x: Int} +72: Pattern Match Exhaustivity: _: Trait & (T1 & (C1 | SubC2)){x: Int} & (T2 & (C2 | C3 | SubC1)){x: Int} & + SubSubC1{x: Int} +79: Pattern Match Exhaustivity: _: Trait & (T1 & (C1 | SubC2)){x: Int} & (T2 & (C2 | C3 | SubC1)){x: Int} & + SubSubC2{x: Int} diff --git a/tests/patmat/exhausting.scala b/tests/patmat/exhausting.scala index 03e8198dd075..75daf4b9112a 100644 --- a/tests/patmat/exhausting.scala +++ b/tests/patmat/exhausting.scala @@ -2,7 +2,7 @@ object Test { sealed abstract class Foo[T] case object Bar1 extends Foo[Int] case object Bar2 extends Foo[String] - case object Bar3 extends Foo[Any] + case object Bar3 extends Foo[AnyRef] def ex1[T](xs: List[T]) = xs match { case ys: List[_] => "ok" diff --git a/tests/patmat/partial-function.check b/tests/patmat/partial-function.check new file mode 100644 index 000000000000..fdfa33c052a8 --- /dev/null +++ b/tests/patmat/partial-function.check @@ -0,0 +1 @@ +10: Pattern Match Exhaustivity: CC(_, B2) From 0de804129416428bf5020d9f30302d30eefd4745 Mon Sep 17 00:00:00 2001 From: liu fengyun Date: Fri, 8 Sep 2017 15:09:57 +0200 Subject: [PATCH 103/146] address review --- compiler/src/dotty/tools/dotc/transform/patmat/Space.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index e17b85cbb0f2..da53a106edad 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -411,9 +411,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { /* Erase a type binding according to erasure semantics in pattern matching */ def erase(tp: Type): Type = tp match { - case tp@AppliedType(tycon, args) => erase(tp.superType) + case tp @ AppliedType(tycon, args) => if (tycon.isRef(defn.ArrayClass)) tp.derivedAppliedType(tycon, args.map(erase)) - else tp.derivedAppliedType(tycon, args.map(t => WildcardType(TypeBounds.empty))) + else tp.derivedAppliedType(tycon, args.map(t => WildcardType)) case OrType(tp1, tp2) => OrType(erase(tp1), erase(tp2)) case AndType(tp1, tp2) => @@ -583,7 +583,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic { val typeParamMap = new TypeMap { def apply(t: Type): Type = t match { - case tp: TypeRef if tp.underlying.isInstanceOf[TypeBounds] => + case tp: TypeRef if tp.symbol.is(TypeParam) && tp.underlying.isInstanceOf[TypeBounds] => // See tests/patmat/gadt.scala tests/patmat/exhausting.scala val bound = if (variance == 0) tp.underlying.bounds // non-variant case is not well-founded From ad04a986e9b67994cabec75405b519949546c8c4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 13:04:41 +0200 Subject: [PATCH 104/146] Address reviewers comments - explain why checkRealizable better - add test case for bad bounds in basetypes - drop dead code - documentation fixes - fixes to lubArgs/glbArgs --- .../tools/dotc/core/CheckRealizable.scala | 7 +++-- .../tools/dotc/core/ConstraintHandling.scala | 5 ++-- .../dotty/tools/dotc/core/Definitions.scala | 3 --- .../dotty/tools/dotc/core/Denotations.scala | 7 ++--- .../dotty/tools/dotc/core/TypeComparer.scala | 27 ++++++++++++++----- .../src/dotty/tools/dotc/core/Types.scala | 8 +++--- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- tests/neg/wildbase.scala | 5 ++++ tests/pos/andtypes.scala | 12 +++++++++ 9 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 tests/neg/wildbase.scala create mode 100644 tests/pos/andtypes.scala diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala index 67ff6f505335..8a775f5a3563 100644 --- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -101,6 +101,9 @@ class CheckRealizable(implicit ctx: Context) { * - all type members have good bounds * - all base types are class types, and if their arguments are wildcards * they have good bounds. + * - base types do not appear in multiple instances with different arguments. + * (depending on the simplification scheme for AndTypes employed, this could + * also lead to base types with bad bounds). */ private def boundsRealizability(tp: Type) = { val mbrProblems = @@ -109,7 +112,7 @@ class CheckRealizable(implicit ctx: Context) { if !(mbr.info.loBound <:< mbr.info.hiBound) } yield new HasProblemBounds(mbr) - + def baseTypeProblems(base: Type) = base match { case AndType(base1, base2) => new HasProblemBase(base1, base2) :: Nil @@ -121,7 +124,7 @@ class CheckRealizable(implicit ctx: Context) { } val baseProblems = tp.baseClasses.map(_.baseTypeOf(tp)).flatMap(baseTypeProblems) - + (((Realizable: Realizability) /: mbrProblems)(_ andAlso _) /: baseProblems)(_ andAlso _) diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index 69f2666d6f18..25f6a05a36e8 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -194,13 +194,12 @@ trait ConstraintHandling { final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = { val avoidParam = new TypeMap { override def stopAtStatic = true - def avoidInArg(arg: Type, formal: TypeParamInfo): Type = + def avoidInArg(arg: Type): Type = if (param.occursIn(arg)) TypeBounds.empty else arg def apply(tp: Type) = mapOver { tp match { case tp @ AppliedType(tycon, args) => - tp.derivedAppliedType(tycon, - args.zipWithConserve(tycon.typeParams)(avoidInArg)) + tp.derivedAppliedType(tycon, args.mapConserve(avoidInArg)) case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent case tp: WildcardType => diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index ca879d95e03b..f246dc1a165a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -78,9 +78,6 @@ class Definitions { val cls = denot.asClass.classSymbol val paramDecls = newScope val typeParam = enterSyntheticTypeParam(cls, paramFlags, paramDecls) - def instantiate(tpe: Type) = - if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.typeRef) - else tpe.dealias val parents = parentConstrs.toList denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parents, paramDecls) } diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 1041ca74cfe9..dc1392761fd6 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -644,12 +644,13 @@ object Denotations { // ------ Forming types ------------------------------------------- /** The TypeRef representing this type denotation at its original location. */ - def appliedRef(implicit ctx: Context): Type = - typeRef.appliedTo(symbol.typeParams.map(_.typeRef)) - def typeRef(implicit ctx: Context): TypeRef = TypeRef(symbol.owner.thisType, symbol.name.asTypeName, this) + /** The typeRef applied to its own type parameters */ + def appliedRef(implicit ctx: Context): Type = + typeRef.appliedTo(symbol.typeParams.map(_.typeRef)) + /** The TermRef representing this term denotation at its original location. */ def termRef(implicit ctx: Context): TermRef = TermRef(symbol.owner.thisType, symbol.name.asTermName, this) diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b94ab60eee33..7153d933df2e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -337,6 +337,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1 @ OrType(tp11, tp12) => def joinOK = tp2.dealias match { case tp2: AppliedType if !tp2.tycon.typeSymbol.isClass => + // If we apply the default algorithm for `A[X] | B[Y] <: C[Z]` where `C` is a + // type parameter, we will instantiate `C` to `A` and then fail when comparing + // with `B[Y]`. To do the right thing, we need to instantiate `C` to the + // common superclass of `A` and `B`. isSubType(tp1.join, tp2) case _ => false @@ -366,7 +370,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { if (cls2.isClass) { val base = tp1.baseType(cls2) if (base.exists) { - if (cls2.is(JavaDefined)) return base.typeSymbol == cls2 + if (cls2.is(JavaDefined)) + // If `cls2` is parameterized, we are seeing a raw type, so we need to compare only the symbol + return base.typeSymbol == cls2 if (base ne tp1) return isSubType(base, tp2) } if (cls2 == defn.SingletonClass && tp1.isStable) return true @@ -689,14 +695,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { * * Returns `true` iff `d >= 0` and `tycon2` can be instantiated to * - * [tparams1_d, ... tparams1_n-1] -> tycon1a[args_1, ..., args_d-1, tparams_d, ... tparams_n-1] + * [tparams1_d, ... tparams1_n-1] -> tycon1[args_1, ..., args_d-1, tparams_d, ... tparams_n-1] * * such that the resulting type application is a supertype of `tp1`. */ def appOK(tp1base: Type) = tp1base match { case tp1base: AppliedType => var tycon1 = tp1base.tycon - var args1 = tp1base.args + val args1 = tp1base.args val tparams1all = tycon1.typeParams val lengthDiff = tparams1all.length - tparams.length lengthDiff >= 0 && { @@ -1244,6 +1250,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { final def lub(tps: List[Type]): Type = ((defn.NothingType: Type) /: tps)(lub(_,_, canConstrain = false)) + /** Try to produce joint arguments for a lub `A[T_1, ..., T_n] | A[T_1', ..., T_n']` using + * the following strategies: + * + * - if arguments are the same, that argument. + * - if corresponding parameter variance is co/contra-variant, the lub/glb. + * - otherwise a TypeBounds containing both arguments + */ def lubArgs(args1: List[Type], args2: List[Type], tparams: List[TypeParamInfo], canConstrain: Boolean = false): List[Type] = tparams match { case tparam :: tparamsRest => @@ -1251,7 +1264,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { val arg2 :: args2Rest = args2 val v = tparam.paramVariance val lubArg = - if (v > 0) lub(arg1.hiBound, arg2.hiBound, canConstrain) + if (isSameTypeWhenFrozen(arg1, arg2)) arg1 + else if (v > 0) lub(arg1.hiBound, arg2.hiBound, canConstrain) else if (v < 0) glb(arg1.loBound, arg2.loBound) else TypeBounds(glb(arg1.loBound, arg2.loBound), lub(arg1.hiBound, arg2.hiBound, canConstrain)) @@ -1263,8 +1277,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { /** Try to produce joint arguments for a glb `A[T_1, ..., T_n] & A[T_1', ..., T_n']` using * the following strategies: * - * - if corresponding parameter variance is co/contra-variant, the glb/lub. * - if arguments are the same, that argument. + * - if corresponding parameter variance is co/contra-variant, the glb/lub. * - if at least one of the arguments if a TypeBounds, the union of * the bounds. * - if homogenizeArgs is set, and arguments can be unified by instantiating @@ -1435,7 +1449,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { private def distributeAnd(tp1: Type, tp2: Type): Type = tp1 match { case tp1 @ AppliedType(tycon1, args1) => tp2 match { - case AppliedType(tycon2, args2) if tycon1.typeSymbol == tycon2.typeSymbol => + case AppliedType(tycon2, args2) + if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 => val jointArgs = glbArgs(args1, args2, tycon1.typeParams) if (jointArgs.forall(_.exists)) (tycon1 & tycon2).appliedTo(jointArgs) else NoType diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c0c271864a44..c431fa4fa9ed 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1032,9 +1032,7 @@ object Types { case tp: AnnotatedType => tp.underlying.underlyingClassRef(refinementOK) case tp: RefinedType => - def isParamName = tp.classSymbol.typeParams.exists(_.name == tp.refinedName) - if (refinementOK || isParamName) tp.underlying.underlyingClassRef(refinementOK) - else NoType + if (refinementOK) tp.underlying.underlyingClassRef(refinementOK) else NoType case tp: RecType => tp.underlying.underlyingClassRef(refinementOK) case _ => @@ -3498,8 +3496,8 @@ object Types { /** Type bounds >: lo <: hi */ abstract case class TypeBounds(lo: Type, hi: Type) extends CachedProxyType with TypeType { - assert(lo.isInstanceOf[TermType]) - assert(hi.isInstanceOf[TermType]) + assert(lo.isInstanceOf[TermType], lo) + assert(hi.isInstanceOf[TermType], hi) override def underlying(implicit ctx: Context): Type = hi diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index c958c2b80178..142669c71212 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -554,7 +554,7 @@ trait Checking { case _ => ctx.error(ex"$tp is not a class type", pos) defn.ObjectType - } + } /** Check that a non-implicit parameter making up the first parameter section of an * implicit conversion is not a singleton type. diff --git a/tests/neg/wildbase.scala b/tests/neg/wildbase.scala new file mode 100644 index 000000000000..b96607ae4e4a --- /dev/null +++ b/tests/neg/wildbase.scala @@ -0,0 +1,5 @@ +class A[T] + +class B extends A[_] // OK + +class C extends A[_ >: Any <: Nothing] // error: conflicting bounds diff --git a/tests/pos/andtypes.scala b/tests/pos/andtypes.scala new file mode 100644 index 000000000000..7537fd223047 --- /dev/null +++ b/tests/pos/andtypes.scala @@ -0,0 +1,12 @@ +class Outer { + type Foo[X] +} + +object Test { + def foo[T](x: T) = x + + def bla[A <: Outer, B <: Outer](a: A, b: B) = { + val x: a.Foo[Int] & b.Foo[Int] = ??? + foo(x) + } +} From a0b691044311619ead268e45438ed21397093941 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 13:59:49 +0200 Subject: [PATCH 105/146] Eliminate some redundant code - eliminate redundant guard - eliminate isClassParam method --- .../src/dotty/tools/dotc/core/Types.scala | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c431fa4fa9ed..5072069dc14a 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -230,7 +230,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 // ??? guard needed ??? + case tp: TypeProxy => tp.underlying.phantomLatticeType case tp: AndOrType => tp.tp1.phantomLatticeType case _ => NoType } @@ -822,9 +822,7 @@ object Types { (this eq thisResult) != (that eq thatResult) && (thisResult matchesLoosely thatResult) } - /** The basetype TypeRef of this type with given class symbol, - * but without including any type arguments - */ + /** The basetype of this type with given class symbol, NoType is `base` is not a class. */ final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ /*>|>*/ track("base type") /*<|<*/ { base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) @@ -843,7 +841,7 @@ object Types { * which may end up calling `&` again, in most cases this should be safe * but because of F-bounded types, this can result in an infinite loop * (which will be masked unless `-Yno-deep-subtypes` is enabled). - * pos/i536 demonstrates that the infinite loop can also invole lower bounds.wait + * pos/i536 demonstrates that the infinite loop can also involve lower bounds. */ def safe_& (that: Type)(implicit ctx: Context): Type = (this, that) match { case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(OrType(lo1, lo2), AndType(hi1, hi2)) @@ -1020,7 +1018,7 @@ object Types { /** 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. + * @param refinementOK If `true` we also skip refinements. */ def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealias match { case tp: TypeRef => @@ -1477,7 +1475,7 @@ object Types { /** Implementations of this trait cache the results of `narrow`. */ trait NarrowCached extends Type { - private var myNarrow: TermRef = null + private[this] var myNarrow: TermRef = null override def narrow(implicit ctx: Context): TermRef = { if (myNarrow eq null) myNarrow = super.narrow myNarrow @@ -1817,9 +1815,6 @@ object Types { } } - def isClassParam(implicit ctx: Context) = // @!!! test flag combination instead? - symbol.is(TypeParam) && symbol.owner.isClass - /** A selection of the same kind, but with potentially a different prefix. * The following normalizations are performed for type selections T#A: * @@ -1836,7 +1831,9 @@ object Types { if (prefix eq this.prefix) this else if (prefix.isBottomType) prefix else if (isType) { - val res = if (isClassParam) argForParam(prefix) else prefix.lookupRefined(name) + val res = + if (symbol.is(ClassTypeParam)) argForParam(prefix) + else prefix.lookupRefined(name) if (res.exists) res else if (Config.splitProjections) prefix match { @@ -2225,8 +2222,8 @@ object Types { } case class LazyRef(private var refFn: Context => Type) extends UncachedProxyType with ValueType { - private var myRef: Type = null - private var computed = false + private[this] var myRef: Type = null + private[this] var computed = false def ref(implicit ctx: Context) = { if (computed) assert(myRef != null) else { @@ -2588,7 +2585,7 @@ object Types { final def isTypeLambda = isInstanceOf[TypeLambda] final def isHigherKinded = isInstanceOf[TypeProxy] - private var myParamRefs: List[ParamRefType] = null + private[this] var myParamRefs: List[ParamRefType] = null def paramRefs: List[ParamRefType] = { if (myParamRefs == null) myParamRefs = paramNames.indices.toList.map(newParamRef) @@ -2683,8 +2680,8 @@ object Types { } else resType - private var myDependencyStatus: DependencyStatus = Unknown - private var myParamDependencyStatus: DependencyStatus = Unknown + private[this] var myDependencyStatus: DependencyStatus = Unknown + private[this] var myParamDependencyStatus: DependencyStatus = Unknown private def depStatus(initial: DependencyStatus, tp: Type)(implicit ctx: Context): DependencyStatus = { def combine(x: DependencyStatus, y: DependencyStatus) = { @@ -3074,8 +3071,8 @@ object Types { abstract case class AppliedType(tycon: Type, args: List[Type]) extends CachedProxyType with ValueType { - private var validSuper: Period = Nowhere - private var cachedSuper: Type = _ + private[this] var validSuper: Period = Nowhere + private[this] var cachedSuper: Type = _ override def underlying(implicit ctx: Context): Type = tycon @@ -3289,7 +3286,7 @@ object Types { def withName(name: Name): this.type = { myRepr = name; this } - private var myRepr: Name = null + private[this] var myRepr: Name = null def repr(implicit ctx: Context): Name = { if (myRepr == null) myRepr = SkolemName.fresh() myRepr @@ -3415,8 +3412,8 @@ object Types { decls: Scope, selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType { - private var selfTypeCache: Type = null - private var appliedRefCache: Type = null + private[this] var selfTypeCache: Type = null + private[this] var appliedRefCache: Type = null /** The self type of a class is the conjunction of * - the explicit self type if given (or the info of a given self symbol), and @@ -3449,7 +3446,7 @@ object Types { def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef(prefix, cls) // cached because baseType needs parents - private var parentsCache: List[Type] = null + private[this] var parentsCache: List[Type] = null override def parents(implicit ctx: Context): List[Type] = { if (parentsCache == null) @@ -3975,8 +3972,7 @@ object Types { } /** Try to widen a named type to its info relative to given prefix `pre`, where possible. - * The possible cases are listed inline in the code. Return `default` if no widening is - * possible. + * The possible cases are listed inline in the code. */ def tryWiden(tp: NamedType, pre: Type): Type = pre.member(tp.name) match { @@ -4008,7 +4004,7 @@ object Types { else pre match { case Range(preLo, preHi) => val forwarded = - if (tp.isClassParam) tp.argForParam(preHi) + if (tp.symbol.is(ClassTypeParam)) tp.argForParam(preHi) else tryWiden(tp, preHi) forwarded.orElse( range(super.derivedSelect(tp, preLo), super.derivedSelect(tp, preHi))) From acb6165091a9d8333c3bdae2a8397e2eb979104a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 15:03:12 +0200 Subject: [PATCH 106/146] Address other reviewer comments --- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 13 +++---------- .../dotty/tools/dotc/transform/ExplicitOuter.scala | 4 ++-- .../src/dotty/tools/dotc/typer/ErrorReporting.scala | 2 +- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index bed373a10cea..cef74648364e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -61,7 +61,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. toPrefix(pre, cls, tp.cls) case _: BoundType | NoPrefix => tp - case tp: RefinedType => //@!!! + case tp: RefinedType => //@!!! todo: remove derivedRefinedType(tp, apply(tp.parent), apply(tp.refinedInfo)) case _ => mapOver(tp) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5072069dc14a..888ae414d65e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4025,11 +4025,7 @@ object Types { case Range(infoLo: TypeBounds, infoHi: TypeBounds) => assert(variance == 0) if (!infoLo.isAlias && !infoHi.isAlias) propagate(infoLo, infoHi) - else range(tp.bottomType, tp.topType) - // Using `parent` instead of `tp.topType` would be better for normal refinements, - // but it would also turn *-types into hk-types, which is not what we want. - // We should revisit this point in case we represent applied types not as refinements anymore. - // @!!! revisit + else range(tp.bottomType, tp.parent) case Range(infoLo, infoHi) => propagate(infoLo, infoHi) case _ => @@ -4112,7 +4108,7 @@ object Types { else tp.derivedAndOrType(tp1, tp2) override protected def derivedTypeArgRef(tp: TypeArgRef, prefix: Type): Type = - if (isRange(prefix)) + if (isRange(prefix)) // TODO: explain tp.underlying match { case TypeBounds(lo, hi) => range(atVariance(-variance)(reapply(lo)), reapply(hi)) case _ => range(tp.bottomType, tp.topType) @@ -4245,10 +4241,7 @@ object Types { this(x, tp.info) case tp @ TypeArgRef(prefix, _, _) => - val saved = variance - variance = 0 - try this(x, prefix) - finally variance = saved + atVariance(0)(this(x, prefix)) case AnnotatedType(underlying, annot) => this(applyToAnnot(x, annot), underlying) diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 83491c19efef..52aa089fca9f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -162,10 +162,10 @@ object ExplicitOuter { * @param flags The flags of the outer accessor * * The type of the outer accessor is computed as follows: - * Let O[X1, .., Xn] be the class eclosing `cls`. + * Let O[X1, .., Xn] be the class enclosing `cls`. * - if owner == cls, O[X1, ..., Xn] * - otherwise, if the class P enclosing `owner` derives from O, the - * base type of P.this of class O + * base type of P.this wrt class O * - otherwise O[_, ..., _] */ private def newOuterSym(owner: ClassSymbol, cls: ClassSymbol, name: TermName, flags: FlagSet)(implicit ctx: Context) = { diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 3b087dd08ae3..83397e4dd532 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -158,7 +158,7 @@ object ErrorReporting { reported.setVariance(-1) val expected1 = reported(expected) val (found2, expected2) = - if (found1 <:< expected1) (found, expected) else (found1, expected1) + if (found1 frozen_<:< expected1) (found, expected) else (found1, expected1) TypeMismatch(found2, expected2, whyNoMatchStr(found, expected), postScript) } From 48a2ab3a68fce48c54ee7f2dcbffb62c96e26879 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 17:27:30 +0200 Subject: [PATCH 107/146] Make hkResult work for curried type lambdas Ensure that hkResult and typeParams are in sync, except that typeParams work also for classes. --- .../tools/dotc/core/TypeApplications.scala | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index 449901579e6a..d013002cb737 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -178,20 +178,17 @@ class TypeApplications(val self: Type) extends AnyVal { if (tsym.isClass) tsym.typeParams else if (!tsym.isCompleting) tsym.info.typeParams else Nil + case self: AppliedType => + if (self.tycon.typeSymbol.isClass) Nil + else self.superType.typeParams case self: ClassInfo => self.cls.typeParams case self: HKTypeLambda => self.typeParams - case self: RefinedType => - self.parent.typeParams - case self: RecType => - self.parent.typeParams - case _: SingletonType => + case _: SingletonType | _: RefinedType | _: RecType => Nil case self: WildcardType => self.optBounds.typeParams - case self: AppliedType if self.tycon.typeSymbol.isClass => - Nil case self: TypeProxy => self.superType.typeParams case _ => @@ -217,15 +214,15 @@ class TypeApplications(val self: Type) extends AnyVal { /** If self type is higher-kinded, its result type, otherwise NoType */ def hkResult(implicit ctx: Context): Type = self.dealias match { case self: TypeRef => self.info.hkResult - case self: RefinedType => NoType - case self: AppliedType => NoType + case self: AppliedType => + if (self.tycon.typeSymbol.isClass) NoType else self.superType.hkResult case self: HKTypeLambda => self.resultType - case self: SingletonType => NoType + case _: SingletonType | _: RefinedType | _: RecType => NoType + case self: WildcardType => self.optBounds.hkResult case self: TypeVar => // Using `origin` instead of `underlying`, as is done for typeParams, // avoids having to set ephemeral in some cases. self.origin.hkResult - case self: WildcardType => self.optBounds.hkResult case self: TypeProxy => self.superType.hkResult case _ => NoType } From fe470c4c722ddadfbe8df520c98247a917659590 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 18:04:49 +0200 Subject: [PATCH 108/146] Adapt reduction of applications to new scheme This allows us to re-instantiate existentials.scala. --- .../tools/dotc/core/TypeApplications.scala | 30 ++++++++----------- tests/{pending => }/neg/existentials.scala | 0 2 files changed, 13 insertions(+), 17 deletions(-) rename tests/{pending => }/neg/existentials.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala index d013002cb737..993feef7f118 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeApplications.scala @@ -81,26 +81,22 @@ object TypeApplications { * `>: L <: H` is substituted for a type lambda parameter `X` only under certain conditions. * * 1. If Mode.AllowLambdaWildcardApply is set: - * The wildcard argument is substituted only if `X` appears in a toplevel refinement of the form + * The wildcard argument is substituted only if `X` appears in a toplevel application of the form * - * { type A = X } + * C[..., X, ...] * * and there are no other occurrences of `X` in the reduced type. In that case * the refinement above is replaced by * - * { type A >: L <: U } + * C[..., _ >: L <: H, ...] * * The `allReplaced` field indicates whether all occurrences of type lambda parameters * in the reduced type have been replaced with arguments. * * 2. If Mode.AllowLambdaWildcardApply is not set: - * All refinements of the form + * All `X` arguments are replaced by: * - * { type A = X } - * - * are replaced by: - * - * { type A >: L <: U } + * _ >: L <: H * * Any other occurrence of `X` in `tycon` is replaced by `U`, if the * occurrence of `X` in `tycon` is covariant, or nonvariant, or by `L`, @@ -121,6 +117,12 @@ object TypeApplications { p.binder == tycon && args(p.paramNum).isInstanceOf[TypeBounds] def canReduceWildcard(p: TypeParamRef) = !ctx.mode.is(Mode.AllowLambdaWildcardApply) || available.contains(p.paramNum) + def atNestedLevel(op: => Type): Type = { + val saved = available + available = Set() + try op + finally available = saved + } // If this is a reference to a reducable type parameter corresponding to a // wildcard argument, return the wildcard argument, otherwise apply recursively. @@ -129,13 +131,10 @@ object TypeApplications { available -= p.paramNum args(p.paramNum) case _ => - apply(arg) + atNestedLevel(apply(arg)) } def apply(t: Type) = t match { - case t @ TypeAlias(p: TypeParamRef) if hasWildcardArg(p) && canReduceWildcard(p) => - available -= p.paramNum // @!!! needed in the future? - args(p.paramNum) case t @ AppliedType(tycon, args1) if tycon.typeSymbol.isClass => t.derivedAppliedType(apply(tycon), args1.mapConserve(applyArg)) case p: TypeParamRef if p.binder == tycon => @@ -148,10 +147,7 @@ object TypeApplications { arg } case _: TypeBounds | _: AppliedType => - val saved = available - available = Set() - try mapOver(t) - finally available = saved + atNestedLevel(mapOver(t)) case _ => mapOver(t) } diff --git a/tests/pending/neg/existentials.scala b/tests/neg/existentials.scala similarity index 100% rename from tests/pending/neg/existentials.scala rename to tests/neg/existentials.scala From 22440f338b7cbb506f283d88d625839ff584b0bb Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 14 Sep 2017 18:29:43 +0200 Subject: [PATCH 109/146] Fix test --- tests/neg/existentials.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neg/existentials.scala b/tests/neg/existentials.scala index a553656729a4..351febc7949b 100644 --- a/tests/neg/existentials.scala +++ b/tests/neg/existentials.scala @@ -44,7 +44,7 @@ class TestX { type D[X] <: C[X] type DD = [X] => D[D[X]] - //val z: DD[_] = ??? // error: unreducible + val z: DD[_] = ??? // error: unreducible val g = x.get From d2b70804a500a566f74df54ec2a9fcde864204b3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 20 Sep 2017 10:50:38 +0200 Subject: [PATCH 110/146] Avoid returning stale symbols from NamedType#symbol There's a scenario where a NamedType is created with an initial symbol but no denotation yet. If the denotation of that NamedType is first computed in a subsequent run, the initially given symbol might be stale, so the symbol should be recomputed from the denotation. --- compiler/src/dotty/tools/dotc/core/Types.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 888ae414d65e..188a0d98ad02 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1737,7 +1737,9 @@ object Types { def symbol(implicit ctx: Context): Symbol = { val now = ctx.period if (checkedPeriod == now || - lastDenotation == null && lastSymbol != null) lastSymbol + lastDenotation == null && lastSymbol != null && + (checkedPeriod.runId == now.runId || ctx.stillValid(lastSymbol))) + lastSymbol else denot.symbol } From 2e65bd581c7506e1a382d906a9c8a961fafabfff Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 20 Sep 2017 17:20:23 +0200 Subject: [PATCH 111/146] Fix stale symbol avoidance --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 3 +++ compiler/src/dotty/tools/dotc/core/Types.scala | 14 ++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index bb3ff7dae021..e37856c9470d 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -420,6 +420,9 @@ object Symbols { pos.exists && defRunId == ctx.runId } + final def isValidInCurrentRun(implicit ctx: Context): Boolean = + lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot) + /** Subclass tests and casts */ final def isTerm(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isTerm diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 188a0d98ad02..013e76504d63 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1570,7 +1570,7 @@ object Types { val d = lastDenotation match { case null => val sym = lastSymbol - if (sym == null) loadDenot else denotOfSym(sym) + if (sym != null && sym.isValidInCurrentRun) denotOfSym(sym) else loadDenot case d: SymDenotation => if (this.isInstanceOf[WithFixedSym]) d.current else if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) @@ -1734,14 +1734,12 @@ object Types { if (reduced.exists) reduced else this } - def symbol(implicit ctx: Context): Symbol = { - val now = ctx.period - if (checkedPeriod == now || - lastDenotation == null && lastSymbol != null && - (checkedPeriod.runId == now.runId || ctx.stillValid(lastSymbol))) + def symbol(implicit ctx: Context): Symbol = + if (checkedPeriod == ctx.period || + lastDenotation == null && lastSymbol != null && lastSymbol.isValidInCurrentRun) lastSymbol - else denot.symbol - } + else + denot.symbol /** Retrieves currently valid symbol without necessarily updating denotation. * Assumes that symbols do not change between periods in the same run. From 38995a3b81885fba49c1ba314854f0f176a37715 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 8 Sep 2017 17:07:38 +0200 Subject: [PATCH 112/146] Allow TermNames to have signed names First step: Handle TermNames whose "name" component (now called "designator" is a SignedName). --- .../src/dotty/tools/dotc/core/Types.scala | 107 +++++++++++------- 1 file changed, 69 insertions(+), 38 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 013e76504d63..363faa1126e9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -7,7 +7,7 @@ import Symbols._ import Flags._ import Names._ import StdNames._, NameOps._ -import NameKinds.{ShadowedName, SkolemName} +import NameKinds.{ShadowedName, SkolemName, SignedName} import Scopes._ import Constants._ import Contexts._ @@ -1488,7 +1488,10 @@ object Types { abstract class NamedType extends CachedProxyType with ValueType { val prefix: Type - val name: Name + val designator: Name + + def name: Name = designator + protected def sig: Signature = Signature.NotAMethod type ThisType >: this.type <: NamedType @@ -1657,8 +1660,6 @@ object Types { |period = ${ctx.phase} at run ${ctx.runId}""") } - protected def sig: Signature = Signature.NotAMethod - private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = if (sig != denot.signature) withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] @@ -1717,10 +1718,14 @@ object Types { def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) - protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = - if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) - else if (!allowPrivate) prefix.nonPrivateMember(name) - else prefix.member(name) + protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { + def recur(desig: Name): Denotation = + if (desig.is(SignedName)) recur(name) + else if (desig.is(ShadowedName)) prefix.nonPrivateMember(desig.exclude(ShadowedName)) + else if (!allowPrivate) prefix.nonPrivateMember(desig) + else prefix.member(desig) + recur(designator) + } /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. @@ -1865,7 +1870,7 @@ object Types { /** Create a NamedType of the same kind as this type, but with a new prefix. */ def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = - NamedType(prefix, name) + NamedType(prefix, designator) /** Create a NamedType of the same kind as this type, but with a "inherited name". * This is necessary to in situations like the following: @@ -1891,11 +1896,11 @@ object Types { * the public name. */ def shadowed(implicit ctx: Context): NamedType = - NamedType(prefix, name.derived(ShadowedName)) + NamedType(prefix, designator.derived(ShadowedName)) override def equals(that: Any) = that match { case that: NamedType => - this.name == that.name && + this.designator == that.designator && this.prefix == that.prefix && !that.isInstanceOf[TermRefWithSignature] && !that.isInstanceOf[WithFixedSym] @@ -1913,7 +1918,7 @@ object Types { */ } - abstract case class TermRef(override val prefix: Type, name: TermName) extends NamedType with SingletonType { + abstract case class TermRef(override val prefix: Type, designator: TermName) extends NamedType with SingletonType { type ThisType = TermRef @@ -1923,12 +1928,14 @@ object Types { if (d.isOverloaded) NoType else d.info } + override def name: TermName = designator + override def signature(implicit ctx: Context): Signature = denot.signature override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef.withSigAndDenot(prefix, name, sd.signature, sd) + TermRef.withSigAndDenot(prefix, designator, sd.signature, sd) def alternatives(implicit ctx: Context): List[TermRef] = denot.alternatives map rewrap @@ -1937,15 +1944,37 @@ object Types { denot.altsWith(p) map rewrap } - abstract case class TypeRef(override val prefix: Type, name: TypeName) extends NamedType { + abstract case class TypeRef(override val prefix: Type, designator: TypeName) extends NamedType { type ThisType = TypeRef + override def name: TypeName = designator + override def underlying(implicit ctx: Context): Type = info } - final class TermRefWithSignature(prefix: Type, name: TermName, override val sig: Signature) extends TermRef(prefix, name) { + final class TermRefWithSignature(prefix: Type, designator: TermName) extends TermRef(prefix, designator) { assert(prefix ne NoPrefix) + + private var mySig: Signature = null + private var myName: TermName = null + + private def decomposeDesignator() = designator match { + case DerivedName(underlying, info: SignedName.SignedInfo) => + mySig = info.sig + myName = underlying + } + + override def sig = { + if (mySig == null) decomposeDesignator() + mySig + } + + override def name = { + if (myName == null) decomposeDesignator() + myName + } + override def signature(implicit ctx: Context) = sig override def loadDenot(implicit ctx: Context): Denotation = { val d = super.loadDenot @@ -1971,22 +2000,20 @@ object Types { sig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) if (newSig ne sig) core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") - fixDenot(TermRef.withSig(prefix, name, newSig), prefix) + fixDenot(TermRef.withSig(prefix, designator, newSig), prefix) } override def shadowed(implicit ctx: Context): NamedType = - fixDenot(TermRef.withSig(prefix, name.derived(ShadowedName), sig), prefix) + fixDenot(TermRef.withSig(prefix, designator.derived(ShadowedName), sig), prefix) override def equals(that: Any) = that match { case that: TermRefWithSignature => this.prefix == that.prefix && - this.name == that.name && - this.sig == that.sig + this.designator == that.designator case _ => false } - override def computeHash = doHash((name, sig), prefix) - override def toString = super.toString ++ s"/withSig($sig)" + override def computeHash = doHash(designator, prefix) } trait WithFixedSym extends NamedType { @@ -2013,23 +2040,23 @@ object Types { override def computeHash = unsupported("computeHash") } - final class CachedTermRef(prefix: Type, name: TermName, hc: Int) extends TermRef(prefix, name) { + final class CachedTermRef(prefix: Type, designator: TermName, hc: Int) extends TermRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc override def computeHash = unsupported("computeHash") } - final class CachedTypeRef(prefix: Type, name: TypeName, hc: Int) extends TypeRef(prefix, name) { + final class CachedTypeRef(prefix: Type, designator: TypeName, hc: Int) extends TypeRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc override def computeHash = unsupported("computeHash") } // Those classes are non final as Linker extends them. - class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol, hc: Int) extends TermRef(prefix, name) with WithFixedSym { + class TermRefWithFixedSym(prefix: Type, designator: TermName, val fixedSym: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { myHash = hc } - class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol, hc: Int) extends TypeRef(prefix, name) with WithFixedSym { + class TypeRefWithFixedSym(prefix: Type, designator: TypeName, val fixedSym: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { myHash = hc } @@ -2038,12 +2065,12 @@ object Types { if (Config.checkUnerased) assert(!ctx.phase.erasedTypes) object NamedType { - def apply(prefix: Type, name: Name)(implicit ctx: Context) = - if (name.isTermName) TermRef.all(prefix, name.asTermName) - else TypeRef(prefix, name.asTypeName) - def apply(prefix: Type, name: Name, denot: Denotation)(implicit ctx: Context) = - if (name.isTermName) TermRef(prefix, name.asTermName, denot) - else TypeRef(prefix, name.asTypeName, denot) + def apply(prefix: Type, designator: Name)(implicit ctx: Context) = + if (designator.isTermName) TermRef.all(prefix, designator.asTermName) + else TypeRef(prefix, designator.asTypeName) + 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 withFixedSym(prefix: Type, sym: Symbol)(implicit ctx: Context) = if (sym.isType) TypeRef.withFixedSym(prefix, sym.name.asTypeName, sym.asType) else TermRef.withFixedSym(prefix, sym.name.asTermName, sym.asTerm) @@ -2060,8 +2087,9 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def all(prefix: Type, name: TermName)(implicit ctx: Context): TermRef = { - ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TermRef] + def all(prefix: Type, designator: TermName)(implicit ctx: Context): TermRef = designator match { + case SignedName(underlying, sig) => withSig(prefix, underlying, sig) + case _ => ctx.uniqueNamedTypes.enterIfNew(prefix, designator).asInstanceOf[TermRef] } /** Create term ref referring to given symbol, taking the signature @@ -2075,12 +2103,12 @@ object Types { * from the denotation if it is completed, or creating a term ref without * signature, if denotation is not yet completed. */ - def apply(prefix: Type, name: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { + def apply(prefix: Type, designator: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) apply(prefix, denot.symbol.asTerm) else denot match { - case denot: SymDenotation if denot.isCompleted => withSig(prefix, name, denot.signature) - case _ => all(prefix, name) + case denot: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) + case _ => all(prefix, designator) } } withDenot denot @@ -2117,8 +2145,11 @@ object Types { else withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature) /** Create a term ref with given prefix, name and signature */ - def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef = - unique(new TermRefWithSignature(prefix, name, sig)) + def withSig(prefix: Type, designator: TermName, sig: Signature)(implicit ctx: Context): TermRef = + designator match { + case DerivedName(underlying, _: SignedName.SignedInfo) => withSig(prefix, underlying, sig) + case name => unique(new TermRefWithSignature(prefix, SignedName(name, sig))) + } /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { From 9e8bcefbd44c1393658195e1a803b4fb17e1eaad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 8 Sep 2017 17:53:23 +0200 Subject: [PATCH 113/146] Eliminate loadDenot in TermRefWithSig --- compiler/src/dotty/tools/dotc/core/Types.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 363faa1126e9..9010437336c8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1708,7 +1708,8 @@ object Types { protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = true) if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - d + if (sig eq Signature.OverloadedSignature) d + else d.atSignature(sig).checkUnique 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 @@ -1976,11 +1977,6 @@ object Types { } override def signature(implicit ctx: Context) = sig - override def loadDenot(implicit ctx: Context): Denotation = { - val d = super.loadDenot - if (sig eq Signature.OverloadedSignature) d - else d.atSignature(sig).checkUnique - } private def fixDenot(candidate: TermRef, prefix: Type)(implicit ctx: Context): TermRef = if (symbol.exists && !candidate.symbol.exists) { // recompute from previous symbol @@ -2004,7 +2000,7 @@ object Types { } override def shadowed(implicit ctx: Context): NamedType = - fixDenot(TermRef.withSig(prefix, designator.derived(ShadowedName), sig), prefix) + fixDenot(super.shadowed.asInstanceOf[TermRef], prefix) override def equals(that: Any) = that match { case that: TermRefWithSignature => From 02444c91d64e4a7abc92443b2dd10fee8d0515b2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 8 Sep 2017 18:18:00 +0200 Subject: [PATCH 114/146] Move two more methods from TermRefWithSig to TermRef --- .../src/dotty/tools/dotc/core/Types.scala | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9010437336c8..e0ad570d70d8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1870,8 +1870,7 @@ object Types { /** Create a NamedType of the same kind as this type, but with a new prefix. */ - def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = - NamedType(prefix, designator) + def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType /** Create a NamedType of the same kind as this type, but with a "inherited name". * This is necessary to in situations like the following: @@ -1943,6 +1942,34 @@ object Types { 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 + + def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = { + // If symbol exists, the new signature is the symbol's signature as seen + // from the new prefix, modulo consistency + val newSig = + if (sig == Signature.NotAMethod || !symbol.exists) + sig + else + sig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) + val candidate = + if (newSig ne sig) { + core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") + TermRef.withSig(prefix, designator, newSig) + } + else TermRef.all(prefix, designator) + fixDenot(candidate, prefix) + } + + override def shadowed(implicit ctx: Context): NamedType = + fixDenot(super.shadowed.asInstanceOf[TermRef], prefix) } abstract case class TypeRef(override val prefix: Type, designator: TypeName) extends NamedType { @@ -1952,6 +1979,9 @@ object Types { override def name: TypeName = designator override def underlying(implicit ctx: Context): Type = info + + def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = + TypeRef(prefix, designator) } final class TermRefWithSignature(prefix: Type, designator: TermName) extends TermRef(prefix, designator) { @@ -1978,30 +2008,6 @@ object Types { override def signature(implicit ctx: Context) = sig - 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 - - override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = { - // If symbol exists, the new signature is the symbol's signature as seen - // from the new prefix, modulo consistency - val newSig = - if (sig == Signature.NotAMethod || !symbol.exists) - sig - else - sig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) - if (newSig ne sig) - core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") - fixDenot(TermRef.withSig(prefix, designator, newSig), prefix) - } - - override def shadowed(implicit ctx: Context): NamedType = - fixDenot(super.shadowed.asInstanceOf[TermRef], prefix) - override def equals(that: Any) = that match { case that: TermRefWithSignature => this.prefix == that.prefix && From e46df82dfa3c5673944a69794abf733bdff11f89 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 8 Sep 2017 18:25:27 +0200 Subject: [PATCH 115/146] Drop all references to TermRefWithSignature --- .../src/dotty/tools/dotc/core/Denotations.scala | 12 +++++------- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 13 +++++-------- .../tools/dotc/transform/ParamForwarding.scala | 15 +++++++++------ .../dotty/tools/dotc/transform/PostTyper.scala | 4 ++-- .../src/dotty/tools/dotc/transform/Splitter.scala | 4 +++- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index dc1392761fd6..04c569556626 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -33,11 +33,11 @@ import Decorators.SymbolIteratorDecorator * * Lines ending in a horizontal line mean subtying (right is a subtype of left). * - * NamedType------TermRefWithSignature - * | | Symbol---------ClassSymbol - * | | | | - * | denot | denot | denot | denot - * v v v v + * NamedType + * | Symbol---------ClassSymbol + * | | | + * | denot | denot | denot + * v v v * Denotation-+-----SingleDenotation-+------SymDenotation-+----ClassDenotation * | | * +-----MultiDenotation | @@ -51,8 +51,6 @@ import Decorators.SymbolIteratorDecorator * prefix: Type * name: Name * It has two subtypes: TermRef and TypeRef - * TermRefWithSignature A TermRef that has in addition a signature to select an overloaded variant, with new field - * sig: Signature * Symbol A label for a definition or declaration in one compiler run * ClassSymbol A symbol representing a class * Denotation The meaning of a named type or symbol during a period diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e0ad570d70d8..c2cced94e3a5 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1325,7 +1325,7 @@ object Types { } /** The signature of this type. This is by default NotAMethod, - * but is overridden for PolyTypes, MethodTypes, and TermRefWithSignature types. + * but is overridden for PolyTypes, MethodTypes, and TermRef types. * (the reason why we deviate from the "final-method-with-pattern-match-in-base-class" * pattern is that method signatures use caching, so encapsulation * is improved using an OO scheme). diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index b49232bf1f8a..dbb8192ef950 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -172,19 +172,16 @@ class TreePickler(pickler: TastyPickler) { } } else pickleRef() - case tpe: TermRefWithSignature => - if (tpe.symbol.is(Flags.Package)) picklePackageRef(tpe.symbol) - else { - writeByte(TERMREF) - pickleNameAndSig(tpe.name, tpe.signature); pickleType(tpe.prefix) - } case tpe: NamedType => - if (isLocallyDefined(tpe.symbol)) { + val sym = tpe.symbol + if (sym.is(Flags.Package) && tpe.isTerm) + picklePackageRef(sym) + else if (isLocallyDefined(tpe.symbol) && tpe.signature.eq(Signature.NotAMethod)) { writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) pickleSymRef(tpe.symbol); pickleType(tpe.prefix) } else { writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(tpe.name); pickleType(tpe.prefix) + pickleName(tpe.designator); pickleType(tpe.prefix) } case tpe: ThisType => if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 2836ebcfe44c..da48149e70e3 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -91,12 +91,15 @@ class ParamForwarding(thisTransformer: DenotTransformer) { } def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree.tpe match { - case tpe: TermRefWithSignature - if tpe.sig == Signature.NotAMethod && tpe.symbol.is(Method) => - // It's a param forwarder; adapt the signature - tree.withType( - TermRef.withSig(tpe.prefix, tpe.name, tpe.prefix.memberInfo(tpe.symbol).signature)) - .asInstanceOf[T] + case tpe: TermRef + if tpe.signature == 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 != Signature.NotAMethod) + tree.withType( + TermRef.withSig(tpe.prefix, tpe.name, tpe.prefix.memberInfo(tpe.symbol).signature)) + .asInstanceOf[T] + else tree case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index f620191c5d92..0a5202a60080 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -79,12 +79,12 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran // TODO fill in } - /** If the type of `tree` is a TermRefWithSignature with an underdefined + /** 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: TermRefWithSignature if tpe.signature.isUnderDefined => + 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.withSig(tpe.prefix, tpe.name, tpe.widen.signature)).asInstanceOf[T] case _ => tree diff --git a/compiler/src/dotty/tools/dotc/transform/Splitter.scala b/compiler/src/dotty/tools/dotc/transform/Splitter.scala index dbd9f15e8532..5e6381c3dcea 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splitter.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splitter.scala @@ -55,7 +55,9 @@ class Splitter extends MiniPhaseTransform { thisTransform => val mbr = tp.member(name) if (!mbr.isOverloaded) mbr.asSingleDenotation else tree.tpe match { - case tref: TermRefWithSignature => mbr.atSignature(tref.sig).checkUnique + case tref: TermRef if !tref.signature.isOverloaded => + assert(tref.isInstanceOf[TermRefWithSignature]) + mbr.atSignature(tref.sig).checkUnique case _ => def alts = mbr.alternatives.map(alt => i"$alt: ${alt.info}").mkString(", ") ctx.error(s"cannot disambiguate overloaded members $alts", tree.pos) From 6aa6d3f4f3d5f9d14b9ea632ad21f9fdeee77bd2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Sep 2017 17:11:19 +0200 Subject: [PATCH 116/146] Eliminate TermRefWithSignature --- .../src/dotty/tools/dotc/core/Types.scala | 61 ++++++++----------- .../src/dotty/tools/dotc/core/Uniques.scala | 14 ++--- .../tools/dotc/core/tasty/TreeUnpickler.scala | 6 +- .../dotc/transform/ParamForwarding.scala | 7 +-- .../dotty/tools/dotc/transform/Splitter.scala | 1 - 5 files changed, 37 insertions(+), 52 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c2cced94e3a5..bf7759b7ff87 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1902,7 +1902,6 @@ object Types { case that: NamedType => this.designator == that.designator && this.prefix == that.prefix && - !that.isInstanceOf[TermRefWithSignature] && !that.isInstanceOf[WithFixedSym] case _ => false @@ -1928,9 +1927,30 @@ object Types { if (d.isOverloaded) NoType else d.info } - override def name: TermName = designator + private var mySig: Signature = null + private var myName: TermName = null + + private def decomposeDesignator() = designator match { + case DerivedName(underlying, info: SignedName.SignedInfo) => + mySig = info.sig + myName = underlying + case _ => + myName = designator + mySig = Signature.NotAMethod + } + + override def sig: Signature = { + if (mySig == null) decomposeDesignator() + mySig + } + + override final def name: TermName = { + if (myName == null) decomposeDesignator() + myName + } - override def signature(implicit ctx: Context): Signature = denot.signature + override final def signature(implicit ctx: Context): Signature = + if (name eq designator) denot.signature else sig override def isOverloaded(implicit ctx: Context) = denot.isOverloaded @@ -1984,39 +2004,6 @@ object Types { TypeRef(prefix, designator) } - final class TermRefWithSignature(prefix: Type, designator: TermName) extends TermRef(prefix, designator) { - assert(prefix ne NoPrefix) - - private var mySig: Signature = null - private var myName: TermName = null - - private def decomposeDesignator() = designator match { - case DerivedName(underlying, info: SignedName.SignedInfo) => - mySig = info.sig - myName = underlying - } - - override def sig = { - if (mySig == null) decomposeDesignator() - mySig - } - - override def name = { - if (myName == null) decomposeDesignator() - myName - } - - override def signature(implicit ctx: Context) = sig - - override def equals(that: Any) = that match { - case that: TermRefWithSignature => - this.prefix == that.prefix && - this.designator == that.designator - case _ => - false - } - override def computeHash = doHash(designator, prefix) - } trait WithFixedSym extends NamedType { def fixedSym: Symbol @@ -2150,7 +2137,7 @@ object Types { def withSig(prefix: Type, designator: TermName, sig: Signature)(implicit ctx: Context): TermRef = designator match { case DerivedName(underlying, _: SignedName.SignedInfo) => withSig(prefix, underlying, sig) - case name => unique(new TermRefWithSignature(prefix, SignedName(name, sig))) + case name => ctx.uniqueNamedTypes.enterIfNew(prefix, SignedName(name, sig)).asInstanceOf[TermRef] } /** Create a term ref with given prefix, name, signature, and initial denotation */ diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index 74b755e22c9a..a9281a1f2ab1 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -43,24 +43,24 @@ object Uniques { final class NamedTypeUniques extends HashSet[NamedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: NamedType): Int = x.hash - private def findPrevious(h: Int, prefix: Type, name: Name): NamedType = { + private def findPrevious(h: Int, prefix: Type, designator: Name): NamedType = { var e = findEntryByHash(h) while (e != null) { - if ((e.prefix eq prefix) && (e.name eq name)) return e + if ((e.prefix eq prefix) && (e.designator eq designator)) return e e = nextEntryByHash(h) } e } - def enterIfNew(prefix: Type, name: Name): NamedType = { - val h = doHash(name, prefix) + def enterIfNew(prefix: Type, designator: Name): NamedType = { + val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) def newType = - if (name.isTypeName) new CachedTypeRef(prefix, name.asTypeName, h) - else new CachedTermRef(prefix, name.asTermName, h) + if (designator.isTypeName) new CachedTypeRef(prefix, designator.asTypeName, h) + else new CachedTermRef(prefix, designator.asTermName, h) if (h == NotCached) newType else { - val r = findPrevious(h, prefix, name) + val r = findPrevious(h, prefix, designator) if (r ne null) r else addEntryAfterScan(newType) } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 00c9e7d210e7..59c4ac5b7065 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -280,8 +280,10 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi TypeRef(readType(), name) case TERMREF => readName() match { - case SignedName(name, sig) => TermRef.withSig(readType(), name, sig) - case name => TermRef.all(readType(), name) + case SignedName(name, sig) => + TermRef.withSig(readType(), name, sig) + case name => + TermRef.all(readType(), name) } case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index da48149e70e3..2d919332c6cb 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -95,11 +95,8 @@ class ParamForwarding(thisTransformer: DenotTransformer) { if tpe.signature == 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 != Signature.NotAMethod) - tree.withType( - TermRef.withSig(tpe.prefix, tpe.name, tpe.prefix.memberInfo(tpe.symbol).signature)) - .asInstanceOf[T] - else tree + if (newSig == Signature.NotAMethod) tree + else tree.withType(TermRef.withSig(tpe.prefix, tpe.name, newSig)).asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/Splitter.scala b/compiler/src/dotty/tools/dotc/transform/Splitter.scala index 5e6381c3dcea..3b6af780c6b9 100644 --- a/compiler/src/dotty/tools/dotc/transform/Splitter.scala +++ b/compiler/src/dotty/tools/dotc/transform/Splitter.scala @@ -56,7 +56,6 @@ class Splitter extends MiniPhaseTransform { thisTransform => if (!mbr.isOverloaded) mbr.asSingleDenotation else tree.tpe match { case tref: TermRef if !tref.signature.isOverloaded => - assert(tref.isInstanceOf[TermRefWithSignature]) mbr.atSignature(tref.sig).checkUnique case _ => def alts = mbr.alternatives.map(alt => i"$alt: ${alt.info}").mkString(", ") From dd9269bfd97b4ba93c4092e0067604df8c374615 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 9 Sep 2017 11:54:04 +0200 Subject: [PATCH 117/146] Some simplifications to creation methods # Conflicts: # compiler/src/dotty/tools/dotc/core/Types.scala # compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala --- .../src/dotty/tools/dotc/core/NameOps.scala | 2 ++ .../src/dotty/tools/dotc/core/Types.scala | 21 +++++++------------ .../tools/dotc/core/tasty/TreeUnpickler.scala | 8 ++----- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 3377ef0bda23..c429f4e32882 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -305,5 +305,7 @@ object NameOps { case raw.BANG => UNARY_! case _ => name } + + def withSig(sig: Signature) = SignedName(name.exclude(SignedName), sig) } } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bf7759b7ff87..8f0a95f13705 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1124,7 +1124,7 @@ object Types { /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = name match { - case name: TermName => TermRef.all(this, name) + case name: TermName => TermRef(this, name) case name: TypeName => TypeRef(this, name).reduceProjection } @@ -1984,7 +1984,7 @@ object Types { core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") TermRef.withSig(prefix, designator, newSig) } - else TermRef.all(prefix, designator) + else TermRef(prefix, designator) fixDenot(candidate, prefix) } @@ -2055,7 +2055,7 @@ object Types { object NamedType { def apply(prefix: Type, designator: Name)(implicit ctx: Context) = - if (designator.isTermName) TermRef.all(prefix, designator.asTermName) + if (designator.isTermName) TermRef(prefix, designator.asTermName) else TypeRef(prefix, designator.asTypeName) def apply(prefix: Type, designator: Name, denot: Denotation)(implicit ctx: Context) = if (designator.isTermName) TermRef(prefix, designator.asTermName, denot) @@ -2076,10 +2076,8 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def all(prefix: Type, designator: TermName)(implicit ctx: Context): TermRef = designator match { - case SignedName(underlying, sig) => withSig(prefix, underlying, sig) - case _ => ctx.uniqueNamedTypes.enterIfNew(prefix, designator).asInstanceOf[TermRef] - } + def apply(prefix: Type, designator: TermName)(implicit ctx: Context): TermRef = + ctx.uniqueNamedTypes.enterIfNew(prefix, designator).asInstanceOf[TermRef] /** Create term ref referring to given symbol, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2097,7 +2095,7 @@ object Types { apply(prefix, denot.symbol.asTerm) else denot match { case denot: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) - case _ => all(prefix, designator) + case _ => apply(prefix, designator) } } withDenot denot @@ -2124,7 +2122,7 @@ object Types { // that could have symbol already set making withSym trigger a double-binding error // ./tests/run/absoverride.scala demonstates this else - all(prefix, name) withSym (sym, Signature.NotAMethod) + apply(prefix, name) withSym (sym, Signature.NotAMethod) /** Create a term ref to given symbol, taking the signature from the symbol * (which must be completed). @@ -2135,10 +2133,7 @@ object Types { /** Create a term ref with given prefix, name and signature */ def withSig(prefix: Type, designator: TermName, sig: Signature)(implicit ctx: Context): TermRef = - designator match { - case DerivedName(underlying, _: SignedName.SignedInfo) => withSig(prefix, underlying, sig) - case name => ctx.uniqueNamedTypes.enterIfNew(prefix, SignedName(name, sig)).asInstanceOf[TermRef] - } + apply(prefix, designator.withSig(sig)) /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 59c4ac5b7065..b32f4491678c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -279,12 +279,8 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val name = readName().toTypeName TypeRef(readType(), name) case TERMREF => - readName() match { - case SignedName(name, sig) => - TermRef.withSig(readType(), name, sig) - case name => - TermRef.all(readType(), name) - } + val name = readName() + TermRef(readType(), name) case THIS => ThisType.raw(readType().asInstanceOf[TypeRef]) case RECtype => From 9acb05d7e5d82bd1cfc8224a2a6d0fb8beba5e01 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 12:37:52 +0200 Subject: [PATCH 118/146] Introduce Designator as a superclass of Name and Symbol Make TermRef and TypeRef case classes take designators instead of names. --- .../dotty/tools/dotc/core/Designator.scala | 26 ++++++++++++ .../src/dotty/tools/dotc/core/Names.scala | 6 ++- .../src/dotty/tools/dotc/core/Symbols.scala | 6 ++- .../src/dotty/tools/dotc/core/Types.scala | 41 +++++++++++++------ .../tools/dotc/core/tasty/TreePickler.scala | 9 ++-- 5 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 compiler/src/dotty/tools/dotc/core/Designator.scala diff --git a/compiler/src/dotty/tools/dotc/core/Designator.scala b/compiler/src/dotty/tools/dotc/core/Designator.scala new file mode 100644 index 000000000000..736b0a720a3e --- /dev/null +++ b/compiler/src/dotty/tools/dotc/core/Designator.scala @@ -0,0 +1,26 @@ +package dotty.tools +package dotc +package core + +import Names._ + +/** 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 { + + type ThisName <: Name + + /** Classifiers, to be overridden in implemetations */ + def isName: Boolean = false + def isSymbol: Boolean = false + + def isTermName: Boolean = false + def isTypeName: Boolean = false + } + + type TermDesignator = Designator { type ThisName = TermName } + type TypeDesignator = Designator { type ThisName = TypeName } +} \ 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 d379653aa372..040c9cc7d36a 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -9,6 +9,7 @@ import Texts.Text import Decorators._ import Contexts.Context import StdNames.str +import Designators._ import util.Chars.isIdentifierStart import collection.IndexedSeqOptimized import collection.generic.CanBuildFrom @@ -37,7 +38,7 @@ object Names { * in a name table. A derived term name adds a tag, and possibly a number * or a further simple name to some other name. */ - abstract class Name extends DotClass with PreName { + abstract class Name extends Designator with PreName { /** A type for names of the same kind as this name */ type ThisName <: Name @@ -153,6 +154,9 @@ object Names { /** Does (the last part of) this name end with `str`? */ def endsWith(str: String): Boolean = lastPart.endsWith(str) + /** Designator override */ + override def isName = true + 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/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index e37856c9470d..95bd3fe4eb6d 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -10,6 +10,7 @@ import java.lang.AssertionError import Decorators._ import Symbols._ import Contexts._ +import Designators._ import SymDenotations._ import printing.Texts._ import printing.Printer @@ -385,7 +386,7 @@ object Symbols { * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) */ - class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with ParamInfo with printing.Showable { + class Symbol private[Symbols] (val coord: Coord, val id: Int) extends Designator with ParamInfo with printing.Showable { type ThisName <: Name @@ -423,6 +424,9 @@ object Symbols { final def isValidInCurrentRun(implicit ctx: Context): Boolean = lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot) + /** Overridden from Designator */ + override def isSymbol = true + /** Subclass tests and casts */ final def isTerm(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isTerm diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8f0a95f13705..586730f27990 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -16,6 +16,7 @@ import SymDenotations._ import Decorators._ import Denotations._ import Periods._ +import Designators._ import util.Positions.{Position, NoPosition} import util.Stats._ import util.{DotClass, SimpleMap} @@ -1488,9 +1489,11 @@ object Types { abstract class NamedType extends CachedProxyType with ValueType { val prefix: Type - val designator: Name + val designator: Designator - def name: Name = designator + def designatorName: Name = designator.asInstanceOf[Name] + + def name(implicit ctx: Context): Name = designatorName protected def sig: Signature = Signature.NotAMethod type ThisType >: this.type <: NamedType @@ -1725,7 +1728,7 @@ object Types { else if (desig.is(ShadowedName)) prefix.nonPrivateMember(desig.exclude(ShadowedName)) else if (!allowPrivate) prefix.nonPrivateMember(desig) else prefix.member(desig) - recur(designator) + recur(designatorName) } /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type @@ -1896,7 +1899,7 @@ object Types { * the public name. */ def shadowed(implicit ctx: Context): NamedType = - NamedType(prefix, designator.derived(ShadowedName)) + NamedType(prefix, designatorName.derived(ShadowedName)) override def equals(that: Any) = that match { case that: NamedType => @@ -1917,7 +1920,7 @@ object Types { */ } - abstract case class TermRef(override val prefix: Type, designator: TermName) extends NamedType with SingletonType { + abstract case class TermRef(override val prefix: Type, designator: TermDesignator) extends NamedType with SingletonType { type ThisType = TermRef @@ -1934,9 +1937,12 @@ object Types { case DerivedName(underlying, info: SignedName.SignedInfo) => mySig = info.sig myName = underlying - case _ => + case designator: TermName => myName = designator mySig = Signature.NotAMethod + case designator: TermSymbol @unchecked => + myName = ??? + mySig = ??? } override def sig: Signature = { @@ -1944,7 +1950,7 @@ object Types { mySig } - override final def name: TermName = { + override final def name(implicit ctx: Context): TermName = { if (myName == null) decomposeDesignator() myName } @@ -1955,7 +1961,7 @@ object Types { override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = - TermRef.withSigAndDenot(prefix, designator, sd.signature, sd) + TermRef.withSigAndDenot(prefix, name, sd.signature, sd) def alternatives(implicit ctx: Context): List[TermRef] = denot.alternatives map rewrap @@ -1982,9 +1988,9 @@ object Types { val candidate = if (newSig ne sig) { core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") - TermRef.withSig(prefix, designator, newSig) + TermRef.withSig(prefix, name, newSig) } - else TermRef(prefix, designator) + else TermRef(prefix, designatorName.asTermName) // ### fixDenot(candidate, prefix) } @@ -1992,16 +1998,25 @@ object Types { fixDenot(super.shadowed.asInstanceOf[TermRef], prefix) } - abstract case class TypeRef(override val prefix: Type, designator: TypeName) extends NamedType { + abstract case class TypeRef(override val prefix: Type, designator: TypeDesignator) extends NamedType { type ThisType = TypeRef - override def name: TypeName = designator + private var myName: TypeName = null + + override def name(implicit ctx: Context): TypeName = { + if (myName == null) + myName = designator match { + case name: TypeName => name + case sym: TypeSymbol @unchecked => sym.name + } + myName + } override def underlying(implicit ctx: Context): Type = info def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = - TypeRef(prefix, designator) + TypeRef(prefix, name) // ### } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index dbb8192ef950..6e360c95dc69 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -54,8 +54,6 @@ class TreePickler(pickler: TastyPickler) { } private def pickleName(name: Name): Unit = writeNat(nameIndex(name).index) - private def pickleNameAndSig(name: Name, sig: Signature) = - pickleName(SignedName(name.toTermName, sig)) private def pickleSymRef(sym: Symbol)(implicit ctx: Context) = symRefs.get(sym) match { case Some(label) => @@ -181,7 +179,7 @@ class TreePickler(pickler: TastyPickler) { pickleSymRef(tpe.symbol); pickleType(tpe.prefix) } else { writeByte(if (tpe.isType) TYPEREF else TERMREF) - pickleName(tpe.designator); pickleType(tpe.prefix) + pickleName(tpe.designatorName); pickleType(tpe.prefix) } case tpe: ThisType => if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) @@ -338,8 +336,9 @@ class TreePickler(pickler: TastyPickler) { case _ => name } val sig = tree.tpe.signature - if (name.isTypeName || sig == Signature.NotAMethod) pickleName(realName) - else pickleNameAndSig(realName, sig) + pickleName( + if (name.isTypeName || sig == Signature.NotAMethod) realName + else SignedName(realName.toTermName, sig)) pickleTree(qual) case Apply(fun, args) => writeByte(APPLY) From 60ad8298f8986da4e09c52c5c9cff6f8b9edb3fa Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 12:19:48 +0200 Subject: [PATCH 119/146] Disregard refinements in lifting when checking equality --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 2 ++ docs/docs/reference/multiversal-equality.md | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index c0e1967ede28..54d9dd78939d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -671,6 +671,8 @@ trait Implicits { self: Typer => case TypeBounds(lo, hi) if lo ne hi => apply(hi) case _ => t } + case t: RefinedType => + apply(t.parent) case _ => if (variance > 0) mapOver(t) else t } diff --git a/docs/docs/reference/multiversal-equality.md b/docs/docs/reference/multiversal-equality.md index 1e70a6088104..0e42756d80cb 100644 --- a/docs/docs/reference/multiversal-equality.md +++ b/docs/docs/reference/multiversal-equality.md @@ -89,7 +89,9 @@ The precise rules for equality checking are as follows. 1. A comparison using `x == y` or `x != y` between values `x: T` and `y: U` is legal if either `T` and `U` are the same, or one of the types is a subtype - of the other, or an implicit value of type `scala.Eq[T, U]` is found. + of the "lifted" version of the other type, or an implicit value of type `scala.Eq[T, U]` is found. + See the [description on Github](https://github.com/lampepfl/dotty/issues/1247) for + a definition of lifting. 2. The usual rules for implicit search apply also to `Eq` instances, with one modification: An instance of `scala.Eq.eqAny[T, U]` is @@ -98,5 +100,10 @@ The precise rules for equality checking are as follows. instance if the implicit search for `Eq[T, T]` succeeds and constructs an instance different from `eqAny`. + Here _lifting_ a type `S` means replacing all references to abstract types + in covariant positions of `S` by their upper bound, and to replacing + all refinement types in in covariant positions of `S` by their parent. + The purpose if lifte + More on multiversal equality is found in a [blog post](http://www.scala-lang.org/blog/2016/05/06/multiversal-equality.html) and a [Github issue](https://github.com/lampepfl/dotty/issues/1247). From 7d6305c2beb85eaf72e7be8c1418344f6a353e77 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 18:18:24 +0200 Subject: [PATCH 120/146] Simplify withSym Drop signature parameter. --- .../src/dotty/tools/dotc/core/Types.scala | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 586730f27990..674a440435ec 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1684,13 +1684,10 @@ object Types { checkedPeriod = Nowhere } - private[dotc] def withSym(sym: Symbol, signature: Signature)(implicit ctx: Context): ThisType = - if (sig != signature) - withSig(signature).withSym(sym, signature).asInstanceOf[ThisType] - else { - setSym(sym) - this - } + 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) @@ -2031,7 +2028,7 @@ object Types { this } - override def withSym(sym: Symbol, signature: Signature)(implicit ctx: Context): ThisType = + override def withSym(sym: Symbol)(implicit ctx: Context): this.type = unsupported("withSym") override def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = @@ -2131,20 +2128,20 @@ object Types { if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) withFixedSym(prefix, name, sym) else if (sym.defRunId != NoRunId && sym.isCompleted) - withSig(prefix, name, sym.signature) withSym (sym, sym.signature) + withSig(prefix, name, sym.signature).withSym(sym) // Linker note: // this is problematic, as withSig method could return a hash-consed refference // that could have symbol already set making withSym trigger a double-binding error // ./tests/run/absoverride.scala demonstates this else - apply(prefix, name) withSym (sym, Signature.NotAMethod) + withSig(prefix, name, Signature.NotAMethod).withSym(sym) /** Create a term ref to given symbol, taking the signature from the symbol * (which must be completed). */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) withFixedSym(prefix, sym.name, sym) - else withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature) + else withSig(prefix, sym.name, sym.signature).withSym(sym) /** Create a term ref with given prefix, name and signature */ def withSig(prefix: Type, designator: TermName, sig: Signature)(implicit ctx: Context): TermRef = @@ -2182,7 +2179,7 @@ object Types { */ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = if ((prefix eq NoPrefix) || sym.isFresh) withFixedSym(prefix, name, sym) - else apply(prefix, name).withSym(sym, Signature.NotAMethod) + else apply(prefix, name).withSym(sym) /** Create a type ref with given name and initial denotation */ def apply(prefix: Type, name: TypeName, denot: Denotation)(implicit ctx: Context): TypeRef = { From 1ec670813d0f0bd352139fb7d65e4c9887ff0517 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 18:57:48 +0200 Subject: [PATCH 121/146] Drop sig method in NamedType Use `signature` instead for everything. Thsi requires being more careful not to force anything when we comppute signature. --- .../src/dotty/tools/dotc/core/Types.scala | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 674a440435ec..bc0166220217 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1494,7 +1494,6 @@ object Types { def designatorName: Name = designator.asInstanceOf[Name] def name(implicit ctx: Context): Name = designatorName - protected def sig: Signature = Signature.NotAMethod type ThisType >: this.type <: NamedType @@ -1664,7 +1663,7 @@ object Types { } private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = - if (sig != denot.signature) + if (signature != denot.signature) withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] else { setDenot(denot) @@ -1708,8 +1707,12 @@ object Types { protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = true) if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (sig eq Signature.OverloadedSignature) d - else d.atSignature(sig).checkUnique + if (hasExplicitSignature) { + val sig = signature + if (sig eq Signature.OverloadedSignature) d + else d.atSignature(sig).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 @@ -1747,6 +1750,10 @@ object Types { else denot.symbol + override def signature(implicit ctx: Context): Signature = + if (isType || lastDenotation == null) Signature.NotAMethod + else denot.signature + /** 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. @@ -1760,6 +1767,8 @@ object Types { def isType = isInstanceOf[TypeRef] def isTerm = isInstanceOf[TermRef] + protected def hasExplicitSignature(implicit ctx: Context) = false + /** 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: @@ -1930,30 +1939,30 @@ object Types { private var mySig: Signature = null private var myName: TermName = null - private def decomposeDesignator() = designator match { - case DerivedName(underlying, info: SignedName.SignedInfo) => - mySig = info.sig - myName = underlying - case designator: TermName => - myName = designator - mySig = Signature.NotAMethod - case designator: TermSymbol @unchecked => - myName = ??? - mySig = ??? - } - - override def sig: Signature = { - if (mySig == null) decomposeDesignator() - mySig - } + private def ensureInitialized()(implicit ctx: Context): Unit = + if (myName == null) + designator match { + case DerivedName(underlying, info: SignedName.SignedInfo) => + mySig = info.sig + myName = underlying + case designator: TermName => + myName = designator + case designator: TermSymbol @unchecked => + myName = designator.name + } override final def name(implicit ctx: Context): TermName = { - if (myName == null) decomposeDesignator() + ensureInitialized() myName } + override def hasExplicitSignature(implicit ctx: Context): Boolean = { + ensureInitialized() + mySig != null + } + override final def signature(implicit ctx: Context): Signature = - if (name eq designator) denot.signature else sig + if (hasExplicitSignature) mySig else super.signature override def isOverloaded(implicit ctx: Context) = denot.isOverloaded @@ -1977,14 +1986,15 @@ object Types { def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = { // 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 (sig == Signature.NotAMethod || !symbol.exists) - sig + if (curSig == Signature.NotAMethod || !symbol.exists) + curSig else - sig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) + curSig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) val candidate = - if (newSig ne sig) { - core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") + if (newSig ne curSig) { + core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") TermRef.withSig(prefix, name, newSig) } else TermRef(prefix, designatorName.asTermName) // ### From 8662c767b44094d97a57dd7575cef4b4a8620476 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 19:19:08 +0200 Subject: [PATCH 122/146] Fix paramForwarding It seemes with the new signature scheme we get NoPrefix Termrefs with NotASignature signatures that can still point to methods. Not a problem, except that it confused adaptRef in ParamForwarding. --- compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 2d919332c6cb..fe124424d033 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -92,7 +92,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) { def adaptRef[T <: RefTree](tree: T)(implicit ctx: Context): T = tree.tpe match { case tpe: TermRef - if tpe.signature == Signature.NotAMethod && tpe.symbol.is(Method) => + if tpe.prefix.ne(NoPrefix) && tpe.signature == 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 == Signature.NotAMethod) tree From 5b20c53785a09f4f3b774d189ae2ebd01c0aa40f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 10 Sep 2017 19:50:26 +0200 Subject: [PATCH 123/146] Restrict handling of OverloadedSignature Avoids a special case in loadDenot. --- compiler/src/dotty/tools/dotc/core/Types.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bc0166220217..1dde9df25d8b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1663,7 +1663,7 @@ object Types { } private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = - if (signature != denot.signature) + if (signature != denot.signature && denot.signature.ne(Signature.OverloadedSignature)) withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] else { setDenot(denot) @@ -1707,11 +1707,7 @@ object Types { protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = true) if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (hasExplicitSignature) { - val sig = signature - if (sig eq Signature.OverloadedSignature) d - else d.atSignature(sig).checkUnique - } + if (hasExplicitSignature) d.atSignature(signature).checkUnique else d else { // name has changed; try load in earlier phase and make current val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current @@ -1944,6 +1940,7 @@ object Types { designator match { case DerivedName(underlying, info: SignedName.SignedInfo) => mySig = info.sig + assert(mySig ne Signature.OverloadedSignature) myName = underlying case designator: TermName => myName = designator From 02e268d4476511257c230e6eeaf253914fabf69e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 10:50:32 +0200 Subject: [PATCH 124/146] New classification methods ands casts in Designator --- .../dotty/tools/dotc/core/Designator.scala | 10 +++++--- .../src/dotty/tools/dotc/core/Names.scala | 6 ++++- .../src/dotty/tools/dotc/core/Symbols.scala | 23 +++++++++++-------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Designator.scala b/compiler/src/dotty/tools/dotc/core/Designator.scala index 736b0a720a3e..73a4705fbb49 100644 --- a/compiler/src/dotty/tools/dotc/core/Designator.scala +++ b/compiler/src/dotty/tools/dotc/core/Designator.scala @@ -3,6 +3,7 @@ package dotc package core import Names._ +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. @@ -13,12 +14,15 @@ object Designators { type ThisName <: Name - /** Classifiers, to be overridden in implemetations */ + /** Classifiers and casts, to be overridden in implemetations */ def isName: Boolean = false def isSymbol: Boolean = false - def isTermName: Boolean = false - def isTypeName: Boolean = false + def isTerm(implicit ctx: Context) = false + def isType(implicit ctx: Context) = false + + def asTerm(implicit ctx: Context): TermDesignator = unsupported("asTerm") + def asType(implicit ctx: Context): TypeDesignator = unsupported("asType") } type TermDesignator = Designator { type ThisName = TermName } diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 040c9cc7d36a..17a64f471084 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -154,8 +154,12 @@ object Names { /** Does (the last part of) this name end with `str`? */ def endsWith(str: String): Boolean = lastPart.endsWith(str) - /** Designator override */ + /** Designator overrides */ override def isName = true + 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/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 95bd3fe4eb6d..9c71ecc0469b 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -424,20 +424,23 @@ object Symbols { final def isValidInCurrentRun(implicit ctx: Context): Boolean = lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot) - /** Overridden from Designator */ - override def isSymbol = true - - /** Subclass tests and casts */ - final def isTerm(implicit ctx: Context): Boolean = + /** Designator overrides */ + final override def isSymbol = true + final override def isTerm(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isTerm - - final def isType(implicit ctx: Context): Boolean = + final override def isType(implicit ctx: Context): Boolean = (if (defRunId == ctx.runId) lastDenot else denot).isType + final override 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 = { + assert(isType, s"isType called on not-a-Type $this"); + asInstanceOf[TypeSymbol] + } - final def isClass: Boolean = isInstanceOf[ClassSymbol] - final def asTerm(implicit ctx: Context): TermSymbol = { assert(isTerm, s"asTerm called on not-a-Term $this" ); asInstanceOf[TermSymbol] } - final def asType(implicit ctx: Context): TypeSymbol = { assert(isType, s"isType called on not-a-Type $this"); asInstanceOf[TypeSymbol] } + final def isClass: Boolean = isInstanceOf[ClassSymbol] final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] final def isFresh(implicit ctx: Context) = From a0b7e47b038725a3dcab189cc9662dbc6e2fb767 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 10:57:28 +0200 Subject: [PATCH 125/146] Refactorings Move logic from subclasses into NamedType. Use explicit initialization instead of laziness. --- .../src/dotty/tools/dotc/core/Types.scala | 91 ++++++++----------- .../src/dotty/tools/dotc/core/Uniques.scala | 10 +- 2 files changed, 42 insertions(+), 59 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1dde9df25d8b..1d721a3ad4d1 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1486,18 +1486,45 @@ object Types { // --- NamedTypes ------------------------------------------------------------------ /** A NamedType of the form Prefix # name */ - abstract class NamedType extends CachedProxyType with ValueType { + abstract class NamedType extends CachedProxyType with ValueType { self => + + type ThisType >: this.type <: NamedType + type ThisName <: Name val prefix: Type - val designator: Designator + val designator: Designator { type ThisName = self.ThisName } - def designatorName: Name = designator.asInstanceOf[Name] + assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") - def name(implicit ctx: Context): Name = designatorName + def isType = isInstanceOf[TypeRef] + def isTerm = isInstanceOf[TermRef] - type ThisType >: this.type <: NamedType + private[this] var myName: ThisName = _ + private[this] var mySig: Signature = null + + def designatorName: Name = designator.asInstanceOf[Name] // ### todo: remove + + private[dotc] def init()(implicit ctx: Context): this.type = { + (designator: Designator) match { // dotty shortcoming: need the upcast + case DerivedName(underlying, info: SignedName.SignedInfo) => + myName = underlying.asInstanceOf[ThisName] + mySig = info.sig + assert(mySig ne Signature.OverloadedSignature) + case designator: Name => + myName = designator.asInstanceOf[ThisName] + case designator: Symbol => + myName = designator.name.asInstanceOf[ThisName] + uncheckedSetSym(designator) + } + this + } - assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix") + final def name: ThisName = myName + + final override def signature(implicit ctx: Context): Signature = + if (mySig != null) mySig + else if (isType || lastDenotation == null) Signature.NotAMethod + else denot.signature private[this] var lastDenotation: Denotation = _ private[this] var lastSymbol: Symbol = _ @@ -1707,7 +1734,7 @@ object Types { protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = true) if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation]) - if (hasExplicitSignature) d.atSignature(signature).checkUnique + if (mySig != null) 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 @@ -1746,9 +1773,6 @@ object Types { else denot.symbol - override def signature(implicit ctx: Context): Signature = - if (isType || lastDenotation == null) Signature.NotAMethod - else denot.signature /** Retrieves currently valid symbol without necessarily updating denotation. * Assumes that symbols do not change between periods in the same run. @@ -1760,11 +1784,6 @@ object Types { def info(implicit ctx: Context): Type = denot.info - def isType = isInstanceOf[TypeRef] - def isTerm = isInstanceOf[TermRef] - - protected def hasExplicitSignature(implicit ctx: Context) = false - /** 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: @@ -1925,6 +1944,7 @@ object Types { abstract case class TermRef(override val prefix: Type, designator: TermDesignator) extends NamedType with SingletonType { type ThisType = TermRef + type ThisName = TermName //assert(name.toString != "") override def underlying(implicit ctx: Context): Type = { @@ -1932,35 +1952,6 @@ object Types { if (d.isOverloaded) NoType else d.info } - private var mySig: Signature = null - private var myName: TermName = null - - private def ensureInitialized()(implicit ctx: Context): Unit = - if (myName == null) - designator match { - case DerivedName(underlying, info: SignedName.SignedInfo) => - mySig = info.sig - assert(mySig ne Signature.OverloadedSignature) - myName = underlying - case designator: TermName => - myName = designator - case designator: TermSymbol @unchecked => - myName = designator.name - } - - override final def name(implicit ctx: Context): TermName = { - ensureInitialized() - myName - } - - override def hasExplicitSignature(implicit ctx: Context): Boolean = { - ensureInitialized() - mySig != null - } - - override final def signature(implicit ctx: Context): Signature = - if (hasExplicitSignature) mySig else super.signature - override def isOverloaded(implicit ctx: Context) = denot.isOverloaded private def rewrap(sd: SingleDenotation)(implicit ctx: Context) = @@ -2005,17 +1996,7 @@ object Types { abstract case class TypeRef(override val prefix: Type, designator: TypeDesignator) extends NamedType { type ThisType = TypeRef - - private var myName: TypeName = null - - override def name(implicit ctx: Context): TypeName = { - if (myName == null) - myName = designator match { - case name: TypeName => name - case sym: TypeSymbol @unchecked => sym.name - } - myName - } + type ThisName = TypeName override def underlying(implicit ctx: Context): Type = info diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index a9281a1f2ab1..9af36fd9eef7 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -52,12 +52,13 @@ object Uniques { e } - def enterIfNew(prefix: Type, designator: Name): NamedType = { + def enterIfNew(prefix: Type, designator: Name)(implicit ctx: Context): NamedType = { val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) - def newType = + def newType = { if (designator.isTypeName) new CachedTypeRef(prefix, designator.asTypeName, h) else new CachedTermRef(prefix, designator.asTermName, h) + }.init() if (h == NotCached) newType else { val r = findPrevious(h, prefix, designator) @@ -78,12 +79,13 @@ object Uniques { e } - def enterIfNew(prefix: Type, name: Name, sym: Symbol): NamedType = { + def enterIfNew(prefix: Type, name: Name, sym: Symbol)(implicit ctx: Context): NamedType = { val h = doHash(sym, prefix) if (monitored) recordCaching(h, classOf[WithFixedSym]) - def newType = + def newType = { if (name.isTypeName) new TypeRefWithFixedSym(prefix, name.asTypeName, sym.asInstanceOf[TypeSymbol], h) else new TermRefWithFixedSym(prefix, name.asTermName, sym.asInstanceOf[TermSymbol], h) + }.init() if (h == NotCached) newType else { val r = findPrevious(h, prefix, sym) From 4d7a7367a9a99af70895fd00c767e95d4889bf78 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 11:18:51 +0200 Subject: [PATCH 126/146] Generalize UniqueNamedTypes --- compiler/src/dotty/tools/dotc/core/Types.scala | 7 ++++--- compiler/src/dotty/tools/dotc/core/Uniques.scala | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 1d721a3ad4d1..451d4a21000f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1502,7 +1502,7 @@ object Types { private[this] var myName: ThisName = _ private[this] var mySig: Signature = null - def designatorName: Name = designator.asInstanceOf[Name] // ### todo: remove + def designatorName: Name = designator.asInstanceOf[Name] // ### todo: remove private[dotc] def init()(implicit ctx: Context): this.type = { (designator: Designator) match { // dotty shortcoming: need the upcast @@ -1513,6 +1513,7 @@ object Types { case designator: Name => myName = designator.asInstanceOf[ThisName] case designator: Symbol => + assert(designator.exists) myName = designator.name.asInstanceOf[ThisName] uncheckedSetSym(designator) } @@ -2029,13 +2030,13 @@ object Types { override def computeHash = unsupported("computeHash") } - final class CachedTermRef(prefix: Type, designator: TermName, hc: Int) extends TermRef(prefix, designator) { + final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc override def computeHash = unsupported("computeHash") } - final class CachedTypeRef(prefix: Type, designator: TypeName, hc: Int) extends TypeRef(prefix, designator) { + final class CachedTypeRef(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc override def computeHash = unsupported("computeHash") diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index 9af36fd9eef7..c972cbcc81e8 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._ +import Types._, Symbols._, Contexts._, util.Stats._, Hashable._, Names._, Designators._ import config.Config import util.HashSet @@ -43,7 +43,7 @@ object Uniques { final class NamedTypeUniques extends HashSet[NamedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: NamedType): Int = x.hash - private def findPrevious(h: Int, prefix: Type, designator: Name): NamedType = { + private def findPrevious(h: Int, prefix: Type, designator: Designator): NamedType = { var e = findEntryByHash(h) while (e != null) { if ((e.prefix eq prefix) && (e.designator eq designator)) return e @@ -52,12 +52,12 @@ object Uniques { e } - def enterIfNew(prefix: Type, designator: Name)(implicit ctx: Context): NamedType = { + def enterIfNew(prefix: Type, designator: Designator)(implicit ctx: Context): NamedType = { val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) def newType = { - if (designator.isTypeName) new CachedTypeRef(prefix, designator.asTypeName, h) - else new CachedTermRef(prefix, designator.asTermName, h) + if (designator.isType) new CachedTypeRef(prefix, designator.asType, h) + else new CachedTermRef(prefix, designator.asTerm, h) }.init() if (h == NotCached) newType else { From f7a81e2cf6baaef4287d6456845f6f46d93001b1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 12:01:02 +0200 Subject: [PATCH 127/146] Allow for late initialization of names Needed because we sometimes form NamedTypes with naked symbols. --- compiler/src/dotty/tools/dotc/core/Types.scala | 5 ++--- compiler/src/dotty/tools/dotc/core/Uniques.scala | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 451d4a21000f..a8742aa263e4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1504,7 +1504,7 @@ object Types { def designatorName: Name = designator.asInstanceOf[Name] // ### todo: remove - private[dotc] def init()(implicit ctx: Context): this.type = { + private[dotc] def init(givenName: Name)(implicit ctx: Context): this.type = { (designator: Designator) match { // dotty shortcoming: need the upcast case DerivedName(underlying, info: SignedName.SignedInfo) => myName = underlying.asInstanceOf[ThisName] @@ -1513,8 +1513,7 @@ object Types { case designator: Name => myName = designator.asInstanceOf[ThisName] case designator: Symbol => - assert(designator.exists) - myName = designator.name.asInstanceOf[ThisName] + myName = givenName.asInstanceOf[ThisName] uncheckedSetSym(designator) } this diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index c972cbcc81e8..7070e3882e6c 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -58,7 +58,7 @@ object Uniques { def newType = { if (designator.isType) new CachedTypeRef(prefix, designator.asType, h) else new CachedTermRef(prefix, designator.asTerm, h) - }.init() + }.init(null) if (h == NotCached) newType else { val r = findPrevious(h, prefix, designator) @@ -85,7 +85,7 @@ object Uniques { def newType = { if (name.isTypeName) new TypeRefWithFixedSym(prefix, name.asTypeName, sym.asInstanceOf[TypeSymbol], h) else new TermRefWithFixedSym(prefix, name.asTermName, sym.asInstanceOf[TermSymbol], h) - }.init() + }.init(name) if (h == NotCached) newType else { val r = findPrevious(h, prefix, sym) From 12cd6bbba31cff9f34474b3c99021590e0cb77e3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 15:26:14 +0200 Subject: [PATCH 128/146] Make desigantors of WithFixedSym classes symbols Thsi will be cleaned up further in next commit. --- .../backend/jvm/DottyBackendInterface.scala | 6 ++-- .../src/dotty/tools/dotc/core/TypeOps.scala | 4 +-- .../src/dotty/tools/dotc/core/Types.scala | 35 +++++++++++-------- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 2 +- .../dotc/transform/PatternMatcherOld.scala | 2 +- .../dotc/transform/localopt/Simplify.scala | 4 +-- .../src/dotty/tools/dotc/typer/Checking.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 4 +-- 9 files changed, 34 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index 40b8412308a4..d75335f09931 100644 --- a/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -431,11 +431,11 @@ class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Ma var found = desugared.get(i.tpe) if (found == null) { i.tpe match { - case TermRef(prefix: TermRef, name) => + case TermRef(prefix: TermRef, _) => found = tpd.ref(prefix).select(i.symbol) - case TermRef(prefix: ThisType, name) => + case TermRef(prefix: ThisType, _) => found = tpd.This(prefix.cls).select(i.symbol) - case TermRef(NoPrefix, name) => + case TermRef(NoPrefix, _) => if (i.symbol is Flags.Method) found = This(i.symbol.topLevelClass).select(i.symbol) // workaround #342 todo: remove after fixed case _ => } diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index cef74648364e..62ed24dc3a7f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -164,9 +164,9 @@ trait TypeOps { this: Context => // TODO: Make standalone object. ctx.typeComparer.lubArgs(args1, args2, tycon1.typeParams)) case _ => fail } - case tp1 @ TypeRef(pre1, name1) => + case tp1 @ TypeRef(pre1, _) => tp2 match { - case tp2 @ TypeRef(pre2, `name1`) => + case tp2 @ TypeRef(pre2, _) if tp1.name eq tp2.name => tp1.derivedSelect(pre1 | pre2) case _ => fail } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index a8742aa263e4..56c7b4b33356 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1746,12 +1746,11 @@ object Types { def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { - def recur(desig: Name): Denotation = - if (desig.is(SignedName)) recur(name) - else if (desig.is(ShadowedName)) prefix.nonPrivateMember(desig.exclude(ShadowedName)) - else if (!allowPrivate) prefix.nonPrivateMember(desig) - else prefix.member(desig) - recur(designatorName) + def recur(name: Name): Denotation = + if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) + else if (!allowPrivate) prefix.nonPrivateMember(name) + else prefix.member(name) + recur(name) } /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type @@ -2006,7 +2005,8 @@ object Types { trait WithFixedSym extends NamedType { - def fixedSym: Symbol + def fixedSym: Symbol = designator.asInstanceOf[Symbol] + assert(fixedSym ne null) assert(fixedSym ne NoSymbol) uncheckedSetSym(fixedSym) @@ -2027,6 +2027,13 @@ object Types { case _ => false } override def computeHash = unsupported("computeHash") + + def checkInst(n: Name, sym: Symbol)(implicit ctx: Context): this.type = { + //assert(name == n, i"bad name: ${name.debugString}, expected: ${n.debugString}, ${System.identityHashCode(name)}, ${System.identityHashCode(n)}") + //assert(fixedSym eq sym) + //assert(symbol eq sym) + this + } } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { @@ -2042,10 +2049,10 @@ object Types { } // Those classes are non final as Linker extends them. - class TermRefWithFixedSym(prefix: Type, designator: TermName, val fixedSym: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { + class TermRefWithFixedSym(prefix: Type, d: Name, designator: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { myHash = hc } - class TypeRefWithFixedSym(prefix: Type, designator: TypeName, val fixedSym: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { + class TypeRefWithFixedSym(prefix: Type, d: Name, designator: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { myHash = hc } @@ -2103,7 +2110,7 @@ object Types { * with given prefix, name, and signature */ def withFixedSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRef] + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRefWithFixedSym].checkInst(name, sym) /** Create a term ref referring to given symbol with given name, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2157,7 +2164,7 @@ object Types { * with given prefix, name, and symbol. */ def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRef] + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRefWithFixedSym].checkInst(name, sym) /** Create a type ref referring to given symbol with given name. * This is very similar to TypeRef(Type, Symbol), @@ -2374,7 +2381,7 @@ object Types { normalize(tp.parent.substRecThis(tp, rt.recThis)) case tp @ RefinedType(parent, rname, rinfo) => val rinfo1 = rinfo match { - case TypeAlias(TypeRef(RecThis(`rt`), `rname`)) => TypeBounds.empty + case TypeAlias(ref @ TypeRef(RecThis(`rt`), _)) if ref.name == rname => TypeBounds.empty case _ => rinfo } tp.derivedRefinedType(normalize(parent), rname, rinfo1) @@ -2682,7 +2689,7 @@ object Types { if (dependencyStatus == FalseDeps) { // dealias all false dependencies val dealiasMap = new TypeMap { def apply(tp: Type) = tp match { - case tp @ TypeRef(pre, name) => + case tp @ TypeRef(pre, _) => tp.info match { case TypeAlias(alias) if depStatus(NoDeps, pre) == TrueDeps => apply(alias) case _ => mapOver(tp) @@ -4432,7 +4439,7 @@ object Types { ) map (_.toTypeName) def isWatched(tp: Type) = tp match { - case TypeRef(_, name) => watchList contains name + case ref: TypeRef => watchList contains ref.name case _ => false } diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index ad2b74d73890..1d13a9460e62 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -630,7 +630,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas // unless names match up. val isBound = (tp: Type) => { def refersTo(tp: Type, sym: Symbol): Boolean = tp match { - case tp @ TypeRef(_, name) => sym.name == name && sym == tp.symbol + case tp: TypeRef => sym.name == tp.name && sym == tp.symbol case tp: TypeVar => refersTo(tp.underlying, sym) case tp : LazyRef => refersTo(tp.ref, sym) case _ => false diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 5007f31007d6..d2bcabb378b0 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -757,7 +757,7 @@ object PatternMatcher { // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` // generates an outer test based on `patType.prefix` with automatically dealises. expectedTp.dealias match { - case tref @ TypeRef(pre: SingletonType, name) => + case tref @ TypeRef(pre: SingletonType, _) => tref.symbol.isClass && ExplicitOuter.needsOuterIfReferenced(tref.symbol.asClass) case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala index 4f196280c2de..122ecd83eb63 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcherOld.scala @@ -799,7 +799,7 @@ class PatternMatcherOld extends MiniPhaseTransform with DenotTransformer { // See the test for SI-7214 for motivation for dealias. Later `treeCondStrategy#outerTest` // generates an outer test based on `patType.prefix` with automatically dealises. expectedTp.dealias match { - case tref @ TypeRef(pre: SingletonType, name) => + case tref @ TypeRef(pre: SingletonType, _) => val s = tref s.symbol.isClass && ExplicitOuter.needsOuterIfReferenced(s.symbol.asClass) diff --git a/compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala b/compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala index bca4b0f65ba7..d453b8f278b4 100644 --- a/compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala +++ b/compiler/src/dotty/tools/dotc/transform/localopt/Simplify.scala @@ -148,9 +148,9 @@ object Simplify { // TODO: This function is duplicated in jvm/DottyBackendInterface.scala, let's factor these out! def desugarIdent(i: Ident)(implicit ctx: Context): Option[Select] = { i.tpe match { - case TermRef(prefix: TermRef, name) => + case TermRef(prefix: TermRef, _) => Some(ref(prefix).select(i.symbol)) - case TermRef(prefix: ThisType, name) => + case TermRef(prefix: ThisType, _) => Some(This(prefix.cls).select(i.symbol)) case _ => None } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 142669c71212..6ee57d5cd220 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -219,7 +219,7 @@ object Checking { tp.derivedRefinedType(this(parent), name, this(rinfo, nestedCycleOK, nestedCycleOK)) case tp: RecType => tp.rebind(this(tp.parent)) - case tp @ TypeRef(pre, name) => + case tp @ TypeRef(pre, _) => try { // A prefix is interesting if it might contain (transitively) a reference // to symbol `sym` itself. We only check references with interesting diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c619d5bd4471..1089076f60cb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -924,9 +924,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val indexPattern = new TreeMap { val elimWildcardSym = new TypeMap { def apply(t: Type) = t match { - case ref @ TypeRef(_, tpnme.WILDCARD) if ctx.gadt.bounds.contains(ref.symbol) => + case ref: TypeRef if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) => ctx.gadt.bounds(ref.symbol) - case TypeAlias(ref @ TypeRef(_, tpnme.WILDCARD)) if ctx.gadt.bounds.contains(ref.symbol) => + case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && ctx.gadt.bounds.contains(ref.symbol) => ctx.gadt.bounds(ref.symbol) case _ => mapOver(t) From fea46e0321048da70ec07827576805c5af3b0fd5 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 15:42:00 +0200 Subject: [PATCH 129/146] Cleanups --- .../src/dotty/tools/dotc/core/Types.scala | 39 +++++++------------ .../src/dotty/tools/dotc/core/Uniques.scala | 8 ++-- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 56c7b4b33356..46e4aa93a18c 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1504,7 +1504,7 @@ object Types { def designatorName: Name = designator.asInstanceOf[Name] // ### todo: remove - private[dotc] def init(givenName: Name)(implicit ctx: Context): this.type = { + private[dotc] def init()(implicit ctx: Context): this.type = { (designator: Designator) match { // dotty shortcoming: need the upcast case DerivedName(underlying, info: SignedName.SignedInfo) => myName = underlying.asInstanceOf[ThisName] @@ -1513,13 +1513,15 @@ object Types { case designator: Name => myName = designator.asInstanceOf[ThisName] case designator: Symbol => - myName = givenName.asInstanceOf[ThisName] uncheckedSetSym(designator) } this } - final def name: ThisName = myName + final def name(implicit ctx: Context): ThisName = { + if (myName == null) myName = designator.asInstanceOf[Symbol].name.asInstanceOf[ThisName] + myName + } final override def signature(implicit ctx: Context): Signature = if (mySig != null) mySig @@ -1745,13 +1747,10 @@ object Types { def reloadDenot()(implicit ctx: Context) = setDenot(loadDenot) - protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = { - def recur(name: Name): Denotation = - if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) - else if (!allowPrivate) prefix.nonPrivateMember(name) - else prefix.member(name) - recur(name) - } + protected def asMemberOf(prefix: Type, allowPrivate: Boolean)(implicit ctx: Context): Denotation = + if (name.is(ShadowedName)) prefix.nonPrivateMember(name.exclude(ShadowedName)) + else if (!allowPrivate) prefix.nonPrivateMember(name) + else prefix.member(name) /** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type * to an (unbounded) wildcard type. @@ -2006,9 +2005,6 @@ object Types { trait WithFixedSym extends NamedType { def fixedSym: Symbol = designator.asInstanceOf[Symbol] - assert(fixedSym ne null) - assert(fixedSym ne NoSymbol) - uncheckedSetSym(fixedSym) override def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { assert(denot.symbol eq fixedSym) @@ -2027,13 +2023,6 @@ object Types { case _ => false } override def computeHash = unsupported("computeHash") - - def checkInst(n: Name, sym: Symbol)(implicit ctx: Context): this.type = { - //assert(name == n, i"bad name: ${name.debugString}, expected: ${n.debugString}, ${System.identityHashCode(name)}, ${System.identityHashCode(n)}") - //assert(fixedSym eq sym) - //assert(symbol eq sym) - this - } } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { @@ -2049,10 +2038,10 @@ object Types { } // Those classes are non final as Linker extends them. - class TermRefWithFixedSym(prefix: Type, d: Name, designator: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { + class TermRefWithFixedSym(prefix: Type, designator: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { myHash = hc } - class TypeRefWithFixedSym(prefix: Type, d: Name, designator: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { + class TypeRefWithFixedSym(prefix: Type, designator: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { myHash = hc } @@ -2110,7 +2099,7 @@ object Types { * with given prefix, name, and signature */ def withFixedSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRefWithFixedSym].checkInst(name, sym) + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRef] /** Create a term ref referring to given symbol with given name, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2164,7 +2153,7 @@ object Types { * with given prefix, name, and symbol. */ def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRefWithFixedSym].checkInst(name, sym) + ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRef] /** Create a type ref referring to given symbol with given name. * This is very similar to TypeRef(Type, Symbol), @@ -4438,7 +4427,7 @@ object Types { val watchList = List[String]( ) map (_.toTypeName) - def isWatched(tp: Type) = tp match { + def isWatched(tp: Type)(implicit ctx: Context) = tp match { case ref: TypeRef => watchList contains ref.name case _ => false } diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index 7070e3882e6c..da07237e6f26 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -58,7 +58,7 @@ object Uniques { def newType = { if (designator.isType) new CachedTypeRef(prefix, designator.asType, h) else new CachedTermRef(prefix, designator.asTerm, h) - }.init(null) + }.init() if (h == NotCached) newType else { val r = findPrevious(h, prefix, designator) @@ -83,9 +83,9 @@ object Uniques { val h = doHash(sym, prefix) if (monitored) recordCaching(h, classOf[WithFixedSym]) def newType = { - if (name.isTypeName) new TypeRefWithFixedSym(prefix, name.asTypeName, sym.asInstanceOf[TypeSymbol], h) - else new TermRefWithFixedSym(prefix, name.asTermName, sym.asInstanceOf[TermSymbol], h) - }.init(name) + if (name.isTypeName) new TypeRefWithFixedSym(prefix, sym.asInstanceOf[TypeSymbol], h) + else new TermRefWithFixedSym(prefix, sym.asInstanceOf[TermSymbol], h) + }.init() if (h == NotCached) newType else { val r = findPrevious(h, prefix, sym) From 6bca2da5fe82a17cdd5321d37002371e698e0c69 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 17:53:07 +0200 Subject: [PATCH 130/146] Get rid of FixedSymUniques --- .../src/dotty/tools/dotc/core/Contexts.scala | 4 -- .../src/dotty/tools/dotc/core/Uniques.scala | 41 +++++-------------- 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index ea931ba75301..df330c4da0b5 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -614,13 +614,9 @@ object Contexts { /** A table for hash consing unique named types */ private[core] val uniqueNamedTypes = new NamedTypeUniques - /** A table for hash consing unique symbolic named types */ - private[core] val uniqueWithFixedSyms = new WithFixedSymUniques - private def uniqueSets = Map( "uniques" -> uniques, "uniqueAppliedTypes" -> uniqueAppliedTypes, - "uniqueWithFixedSyms" -> uniqueWithFixedSyms, "uniqueNamedTypes" -> uniqueNamedTypes) /** A map that associates label and size of all uniques sets */ diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index da07237e6f26..33a7b433653a 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -52,12 +52,20 @@ object Uniques { e } - def enterIfNew(prefix: Type, designator: Designator)(implicit ctx: Context): NamedType = { + 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 (designator.isType) new CachedTypeRef(prefix, designator.asType, h) - else new CachedTermRef(prefix, designator.asTerm, h) + if (isTerm) + designator match { + case designator: TermSymbol => new TermRefWithFixedSym(prefix, designator, h) + case _ => new CachedTermRef(prefix, designator.asTerm, h) + } + else + designator match { + case designator: TypeSymbol => new TypeRefWithFixedSym(prefix, designator, h) + case _ => new CachedTypeRef(prefix, designator.asType, h) + } }.init() if (h == NotCached) newType else { @@ -67,33 +75,6 @@ object Uniques { } } - final class WithFixedSymUniques extends HashSet[WithFixedSym](Config.initialUniquesCapacity) with Hashable { - override def hash(x: WithFixedSym): Int = x.hash - - private def findPrevious(h: Int, prefix: Type, sym: Symbol): NamedType = { - var e = findEntryByHash(h) - while (e != null) { - if ((e.prefix eq prefix) && (e.fixedSym eq sym)) return e - e = nextEntryByHash(h) - } - e - } - - def enterIfNew(prefix: Type, name: Name, sym: Symbol)(implicit ctx: Context): NamedType = { - val h = doHash(sym, prefix) - if (monitored) recordCaching(h, classOf[WithFixedSym]) - def newType = { - if (name.isTypeName) new TypeRefWithFixedSym(prefix, sym.asInstanceOf[TypeSymbol], h) - else new TermRefWithFixedSym(prefix, sym.asInstanceOf[TermSymbol], h) - }.init() - if (h == NotCached) newType - else { - val r = findPrevious(h, prefix, sym) - if (r ne null) r else addEntryAfterScan(newType) - } - } - } - final class AppliedUniques extends HashSet[AppliedType](Config.initialUniquesCapacity) with Hashable { override def hash(x: AppliedType): Int = x.hash From a3c69a5f316ba9efdb8ad9742621a7151ead539e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 17:54:25 +0200 Subject: [PATCH 131/146] Get rid of FixedSymUniques --- .../src/dotty/tools/dotc/core/Types.scala | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 46e4aa93a18c..78d300907451 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1923,12 +1923,13 @@ object Types { override def equals(that: Any) = that match { case that: NamedType => this.designator == that.designator && - this.prefix == that.prefix && - !that.isInstanceOf[WithFixedSym] + this.prefix == that.prefix case _ => false } + override def computeHash = unsupported("computeHash") + /* A version of toString which also prints aliases. Can be used for debugging override def toString = if (isTerm) s"TermRef($prefix, $name)" @@ -2017,24 +2018,16 @@ object Types { override def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = NamedType.withFixedSym(prefix, fixedSym) - - override def equals(that: Any) = that match { - case that: WithFixedSym => this.prefix == that.prefix && (this.fixedSym eq that.fixedSym) - case _ => false - } - override def computeHash = unsupported("computeHash") } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc - override def computeHash = unsupported("computeHash") } final class CachedTypeRef(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) { assert(prefix ne NoPrefix) myHash = hc - override def computeHash = unsupported("computeHash") } // Those classes are non final as Linker extends them. @@ -2073,7 +2066,7 @@ object Types { * of prefix with given name. */ def apply(prefix: Type, designator: TermName)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, designator).asInstanceOf[TermRef] + ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] /** Create term ref referring to given symbol, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2099,7 +2092,7 @@ object Types { * with given prefix, name, and signature */ def withFixedSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TermRef] + ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = true).asInstanceOf[TermRef] /** Create a term ref referring to given symbol with given name, taking the signature * from the symbol if it is completed, or creating a term ref without @@ -2143,7 +2136,7 @@ object Types { object TypeRef { /** Create type ref with given prefix and name */ def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, name).asInstanceOf[TypeRef] + ctx.uniqueNamedTypes.enterIfNew(prefix, name, isTerm = false).asInstanceOf[TypeRef] /** Create type ref to given symbol */ def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = @@ -2153,7 +2146,7 @@ object Types { * with given prefix, name, and symbol. */ def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - ctx.uniqueWithFixedSyms.enterIfNew(prefix, name, sym).asInstanceOf[TypeRef] + ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref referring to given symbol with given name. * This is very similar to TypeRef(Type, Symbol), From d868f33a3b9c651d82275ff56200daaa0759f4de Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 Sep 2017 18:14:36 +0200 Subject: [PATCH 132/146] Get rid of WithFixedSym --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 5 +- .../dotty/tools/dotc/core/Substituters.scala | 6 +- .../tools/dotc/core/SymDenotations.scala | 2 +- .../dotty/tools/dotc/core/TypeComparer.scala | 4 +- .../src/dotty/tools/dotc/core/Types.scala | 93 ++++++++----------- .../src/dotty/tools/dotc/core/Uniques.scala | 12 +-- .../tools/dotc/core/tasty/TreePickler.scala | 25 ++--- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../tools/dotc/transform/TreeChecker.scala | 8 +- 10 files changed, 67 insertions(+), 92 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 40aea19da8f6..5d14b85862ad 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -86,7 +86,10 @@ object Trees { * where we overwrite with a simplified version of the type itself. */ private[dotc] def overwriteType(tpe: T) = { - if (this.isInstanceOf[Template[_]]) assert(tpe.isInstanceOf[WithFixedSym], s"$this <--- $tpe") + if (this.isInstanceOf[Template[_]]) + tpe match { + case tpe: TermRef => assert(tpe.hasFixedSym , s"$this <--- $tpe") + } myTpe = tpe } diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index fabcd5712d26..d81c21521ecf 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -130,9 +130,9 @@ trait Substituters { this: Context => var ts = to while (fs.nonEmpty) { if (fs.head eq sym) - return tp match { - case tp: WithFixedSym => NamedType.withFixedSym(tp.prefix, ts.head) - case _ => substSym(tp.prefix, from, to, theMap) select ts.head + return { + if (tp.hasFixedSym) NamedType.withFixedSym(tp.prefix, ts.head) // ### why the different treatement of prefix? + else 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 07e4f0ed0128..defedd719258 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1136,7 +1136,7 @@ object SymDenotations { TermRef.withSigAndDenot(owner.thisType, name.asTermName, signature, this) def nonMemberTermRef(implicit ctx: Context): TermRef = - TermRef.withFixedSym(owner.thisType, name.asTermName, symbol.asTerm) + TermRef.withFixedSym(owner.thisType, symbol.asTerm) /** The variance of this type parameter or type member as an Int, with * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 7153d933df2e..69d1c2a4454a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -198,8 +198,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { ( (tp1.name eq tp2.name) && isSubType(tp1.prefix, tp2.prefix) && tp1.signature == tp2.signature - && !tp1.isInstanceOf[WithFixedSym] - && !tp2.isInstanceOf[WithFixedSym] + && !tp1.hasFixedSym + && !tp2.hasFixedSym ) || thirdTryNamed(tp1, tp2) case _ => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 78d300907451..e0422a01b432 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1498,6 +1498,7 @@ object Types { def isType = isInstanceOf[TypeRef] def isTerm = isInstanceOf[TermRef] + def hasFixedSym = designator.isInstanceOf[Symbol] private[this] var myName: ThisName = _ private[this] var mySig: Signature = null @@ -1606,7 +1607,7 @@ object Types { val sym = lastSymbol if (sym != null && sym.isValidInCurrentRun) denotOfSym(sym) else loadDenot case d: SymDenotation => - if (this.isInstanceOf[WithFixedSym]) d.current + if (hasFixedSym) d.current else if (d.validFor.runId == ctx.runId || ctx.stillValid(d)) if (d.exists && prefix.isTightPrefix(d.owner) || d.isConstructor) d.current else recomputeMember(d) // symbol could have been overridden, recompute membership @@ -1692,7 +1693,9 @@ object Types { } private[dotc] def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = - if (signature != denot.signature && denot.signature.ne(Signature.OverloadedSignature)) + if (!hasFixedSym && + signature != denot.signature && + denot.signature.ne(Signature.OverloadedSignature)) withSig(denot.signature).withDenot(denot).asInstanceOf[ThisType] else { setDenot(denot) @@ -1970,22 +1973,25 @@ object Types { } else candidate - def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = { - // 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 == Signature.NotAMethod || !symbol.exists) - curSig - else - curSig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) - val candidate = - if (newSig ne curSig) { - core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") - TermRef.withSig(prefix, name, newSig) - } - else TermRef(prefix, designatorName.asTermName) // ### - fixDenot(candidate, prefix) + def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = designator match { + case designator: TermSymbol => + TermRef.withFixedSym(prefix, designator) + case designator: TermName => + // 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 == Signature.NotAMethod || !symbol.exists) + curSig + else + curSig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) + val candidate = + if (newSig ne curSig) { + core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") + TermRef.withSig(prefix, name, newSig) + } + else TermRef(prefix, designator) + fixDenot(candidate, prefix) } override def shadowed(implicit ctx: Context): NamedType = @@ -2000,41 +2006,16 @@ object Types { override def underlying(implicit ctx: Context): Type = info def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = - TypeRef(prefix, name) // ### - } - - - trait WithFixedSym extends NamedType { - def fixedSym: Symbol = designator.asInstanceOf[Symbol] - - override def withDenot(denot: Denotation)(implicit ctx: Context): ThisType = { - assert(denot.symbol eq fixedSym) - setDenot(denot) - this - } - - override def withSym(sym: Symbol)(implicit ctx: Context): this.type = - unsupported("withSym") - - override def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = - NamedType.withFixedSym(prefix, fixedSym) + TypeRef(prefix, designator) } final class CachedTermRef(prefix: Type, designator: TermDesignator, hc: Int) extends TermRef(prefix, designator) { - assert(prefix ne NoPrefix) + assert((prefix ne NoPrefix) || hasFixedSym) myHash = hc } final class CachedTypeRef(prefix: Type, designator: TypeDesignator, hc: Int) extends TypeRef(prefix, designator) { - assert(prefix ne NoPrefix) - myHash = hc - } - - // Those classes are non final as Linker extends them. - class TermRefWithFixedSym(prefix: Type, designator: TermSymbol, hc: Int) extends TermRef(prefix, designator) with WithFixedSym { - myHash = hc - } - class TypeRefWithFixedSym(prefix: Type, designator: TypeSymbol, hc: Int) extends TypeRef(prefix, designator) with WithFixedSym { + assert((prefix ne NoPrefix) || hasFixedSym) myHash = hc } @@ -2050,8 +2031,8 @@ object Types { if (designator.isTermName) TermRef(prefix, designator.asTermName, denot) else TypeRef(prefix, designator.asTypeName, denot) def withFixedSym(prefix: Type, sym: Symbol)(implicit ctx: Context) = - if (sym.isType) TypeRef.withFixedSym(prefix, sym.name.asTypeName, sym.asType) - else TermRef.withFixedSym(prefix, sym.name.asTermName, sym.asTerm) + if (sym.isType) TypeRef.withFixedSym(prefix, sym.asType) + else TermRef.withFixedSym(prefix, sym.asTerm) def withSymAndName(prefix: Type, sym: Symbol, name: Name)(implicit ctx: Context): NamedType = if (sym.isType) TypeRef.withSymAndName(prefix, sym.asType, name.asTypeName) else TermRef.withSymAndName(prefix, sym.asTerm, name.asTermName) @@ -2091,7 +2072,7 @@ object Types { /** Create a non-member term ref (which cannot be reloaded using `member`), * with given prefix, name, and signature */ - def withFixedSym(prefix: Type, name: TermName, sym: TermSymbol)(implicit ctx: Context): TermRef = + def withFixedSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = true).asInstanceOf[TermRef] /** Create a term ref referring to given symbol with given name, taking the signature @@ -2103,7 +2084,7 @@ object Types { */ def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) - withFixedSym(prefix, name, sym) + withFixedSym(prefix, sym) else if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature).withSym(sym) // Linker note: @@ -2117,7 +2098,7 @@ object Types { * (which must be completed). */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) withFixedSym(prefix, sym.name, sym) + if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) withFixedSym(prefix, sym) else withSig(prefix, sym.name, sym.signature).withSym(sym) /** Create a term ref with given prefix, name and signature */ @@ -2127,7 +2108,7 @@ object Types { /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) - withFixedSym(prefix, denot.symbol.asTerm.name, denot.symbol.asTerm) + withFixedSym(prefix, denot.symbol.asTerm) else withSig(prefix, name, sig) } withDenot denot @@ -2135,8 +2116,8 @@ object Types { object TypeRef { /** Create type ref with given prefix and name */ - def apply(prefix: Type, name: TypeName)(implicit ctx: Context): TypeRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, name, isTerm = false).asInstanceOf[TypeRef] + def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = + ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create type ref to given symbol */ def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = @@ -2145,7 +2126,7 @@ object Types { /** Create a non-member type ref (which cannot be reloaded using `member`), * with given prefix, name, and symbol. */ - def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef = + def withFixedSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = false).asInstanceOf[TypeRef] /** Create a type ref referring to given symbol with given name. @@ -2155,7 +2136,7 @@ object Types { * (2) The name in the type ref need not be the same as the name of the Symbol. */ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = - if ((prefix eq NoPrefix) || sym.isFresh) withFixedSym(prefix, name, sym) + if ((prefix eq NoPrefix) || sym.isFresh) withFixedSym(prefix, sym) else apply(prefix, name).withSym(sym) /** Create a type ref with given name and initial denotation */ diff --git a/compiler/src/dotty/tools/dotc/core/Uniques.scala b/compiler/src/dotty/tools/dotc/core/Uniques.scala index 33a7b433653a..fef45d0a4b33 100644 --- a/compiler/src/dotty/tools/dotc/core/Uniques.scala +++ b/compiler/src/dotty/tools/dotc/core/Uniques.scala @@ -56,16 +56,8 @@ object Uniques { val h = doHash(designator, prefix) if (monitored) recordCaching(h, classOf[NamedType]) def newType = { - if (isTerm) - designator match { - case designator: TermSymbol => new TermRefWithFixedSym(prefix, designator, h) - case _ => new CachedTermRef(prefix, designator.asTerm, h) - } - else - designator match { - case designator: TypeSymbol => new TypeRefWithFixedSym(prefix, designator, h) - case _ => new CachedTypeRef(prefix, designator.asType, h) - } + if (isTerm) new CachedTermRef(prefix, designator.asInstanceOf[TermDesignator], h) + else new CachedTypeRef(prefix, designator.asInstanceOf[TypeDesignator], h) }.init() if (h == NotCached) newType else { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 6e360c95dc69..c83a904a257c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -142,7 +142,7 @@ class TreePickler(pickler: TastyPickler) { withLength { pickleType(tycon); args.foreach(pickleType(_)) } case ConstantType(value) => pickleConstant(value) - case tpe: WithFixedSym => + case tpe: NamedType => val sym = tpe.symbol def pickleRef() = if (tpe.prefix == NoPrefix) { @@ -169,21 +169,21 @@ class TreePickler(pickler: TastyPickler) { pickleRef() } } - else pickleRef() - case tpe: NamedType => - val sym = tpe.symbol - if (sym.is(Flags.Package) && tpe.isTerm) - picklePackageRef(sym) - else if (isLocallyDefined(tpe.symbol) && tpe.signature.eq(Signature.NotAMethod)) { + else if (tpe.hasFixedSym) { + pickleRef() + } + else if (isLocallyDefined(sym) && tpe.signature.eq(Signature.NotAMethod)) { writeByte(if (tpe.isType) TYPEREFsymbol else TERMREFsymbol) - pickleSymRef(tpe.symbol); pickleType(tpe.prefix) + pickleSymRef(sym); pickleType(tpe.prefix) } else { writeByte(if (tpe.isType) TYPEREF else TERMREF) pickleName(tpe.designatorName); pickleType(tpe.prefix) } case tpe: ThisType => - if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) - picklePackageRef(tpe.cls) + if (tpe.cls.is(Flags.Package) && !tpe.cls.isEffectiveRoot) { + writeByte(TERMREFpkg) + pickleName(tpe.cls.fullName) + } else { writeByte(THIS) pickleType(tpe.tref) @@ -238,11 +238,6 @@ class TreePickler(pickler: TastyPickler) { pickleType(tpe.ref) } - def picklePackageRef(pkg: Symbol)(implicit ctx: Context): Unit = { - writeByte(TERMREFpkg) - pickleName(pkg.fullName) - } - def pickleMethodic(tag: Int, tpe: LambdaType)(implicit ctx: Context) = { writeByte(tag) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index b32f4491678c..6d2dbcfdaed5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -246,7 +246,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType()) registerSym(start, sym) if (currentAddr != end) readType() - TypeRef.withFixedSym(NoPrefix, sym.name, sym) + TypeRef.withFixedSym(NoPrefix, sym) case POLYtype => readMethodic(PolyType, _.toTypeName) case METHODtype => diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 1d13a9460e62..2ee3f09f9aca 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -735,7 +735,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val tycon = if (sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package)) // used fixed sym for Scala 2 inner classes, because they might be shadowed - TypeRef.withFixedSym(pre, sym.name.asTypeName, sym.asType) + TypeRef.withFixedSym(pre, sym.asType) else if (isLocal(sym) || pre == NoPrefix) { val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre pre1 select sym diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index e99427867883..e2237c187a27 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -320,8 +320,12 @@ class TreeChecker extends Phase with SymTransformer { assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase) val tpe = tree.typeOpt val sym = tree.symbol - if (!tpe.isInstanceOf[WithFixedSym] && - sym.exists && !sym.is(Private) && + val symIsFixed = tpe match { + case tpe: TermRef => tpe.hasFixedSym + case _ => false + } + if (sym.exists && !sym.is(Private) && + !symIsFixed && !tree.name.is(OuterSelectName) // outer selects have effectively fixed symbols ) { val qualTpe = tree.qualifier.typeOpt From 2539e47f8d81b19a7888b1e02898c9053ba775b2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Sep 2017 09:05:34 +0200 Subject: [PATCH 133/146] Renamings of creation methods withfixedSym -> apply It's just apply with a different designator apply(Type, Symbol) -> withSym This one contains special cases. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../dotty/tools/dotc/core/Substituters.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 4 +- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../dotty/tools/dotc/core/TypeErasure.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 53 ++++++++----------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotty/tools/dotc/transform/MixinOps.scala | 4 +- .../dotty/tools/dotc/typer/Applications.scala | 2 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 4 +- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 17 files changed, 44 insertions(+), 51 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 660c4b81de80..e2fbe20591fa 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -97,8 +97,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType)(implicit ctx: Context): Block = { val targetTpt = if (targetType.exists) TypeTree(targetType) else EmptyTree val call = - if (targs.isEmpty) Ident(TermRef(NoPrefix, meth)) - else TypeApply(Ident(TermRef(NoPrefix, meth)), targs) + if (targs.isEmpty) Ident(TermRef.withSym(NoPrefix, meth)) + else TypeApply(Ident(TermRef.withSym(NoPrefix, meth)), targs) Block( DefDef(meth, rhsFn) :: Nil, Closure(Nil, call, targetTpt)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f246dc1a165a..0d669aab7fa8 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -174,7 +174,7 @@ class Definitions { lazy val RootClass: ClassSymbol = ctx.newPackageSymbol( NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass lazy val RootPackage: TermSymbol = ctx.newSymbol( - NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass)) + NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef.withSym(NoPrefix, RootClass)) lazy val EmptyPackageVal = ctx.newPackageSymbol( RootClass, nme.EMPTY_PACKAGE, (emptypkg, emptycls) => ctx.rootLoader(emptypkg)).entered diff --git a/compiler/src/dotty/tools/dotc/core/Substituters.scala b/compiler/src/dotty/tools/dotc/core/Substituters.scala index d81c21521ecf..ce4d4337a1b3 100644 --- a/compiler/src/dotty/tools/dotc/core/Substituters.scala +++ b/compiler/src/dotty/tools/dotc/core/Substituters.scala @@ -131,7 +131,7 @@ trait Substituters { this: Context => while (fs.nonEmpty) { if (fs.head eq sym) return { - if (tp.hasFixedSym) NamedType.withFixedSym(tp.prefix, ts.head) // ### why the different treatement of prefix? + if (tp.hasFixedSym) NamedType(tp.prefix, ts.head) // ### why the different treatement of prefix? else substSym(tp.prefix, from, to, theMap) select ts.head } fs = fs.tail diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index defedd719258..3109a5eb8a6a 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1136,7 +1136,7 @@ object SymDenotations { TermRef.withSigAndDenot(owner.thisType, name.asTermName, signature, this) def nonMemberTermRef(implicit ctx: Context): TermRef = - TermRef.withFixedSym(owner.thisType, symbol.asTerm) + TermRef(owner.thisType, symbol.asTerm) /** The variance of this type parameter or type member as an Int, with * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter @@ -1402,7 +1402,7 @@ object SymDenotations { } private def computeThisType(implicit ctx: Context): Type = - ThisType.raw(TypeRef( + ThisType.raw(TypeRef.withSym( if (this is Package) NoPrefix else owner.thisType, symbol.asType)) private[this] var myTypeRef: TypeRef = null diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 9c71ecc0469b..2f3d42a826dd 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -246,7 +246,7 @@ trait Symbols { this: Context => * would be `fld2`. There is a single local dummy per template. */ def newLocalDummy(cls: Symbol, coord: Coord = NoCoord) = - newSymbol(cls, nme.localDummyName(cls), EmptyFlags, NoType) + newSymbol(cls, nme.localDummyName(cls), Fresh, NoType) /** Create an import symbol pointing back to given qualifier `expr`. */ def newImportSymbol(owner: Symbol, expr: Tree, coord: Coord = NoCoord) = diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 18c58ba6b456..640539246b38 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -150,7 +150,7 @@ object TypeErasure { assert(tp.symbol.exists, tp) val tp1 = ctx.makePackageObjPrefixExplicit(tp) if (tp1 ne tp) erasedRef(tp1) - else TermRef(erasedRef(tp.prefix), tp.symbol.asTerm) + else TermRef.withSym(erasedRef(tp.prefix), tp.symbol.asTerm) case tp: ThisType => tp case tp => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index e0422a01b432..d59418b0e576 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1123,6 +1123,11 @@ object Types { loop(this) } + private def isReferencedSymbolically(sym: Symbol)(implicit ctx: Context) = + sym.isFresh || + sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package) || + ctx.phase.symbolicRefs + /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = name match { case name: TermName => TermRef(this, name) @@ -1137,8 +1142,8 @@ object Types { /** The type with given symbol, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = - if (sym.isTerm) TermRef(this, sym.asTerm) - else TypeRef(this, sym.asType).reduceProjection + if (sym.isTerm) TermRef.withSym(this, sym.asTerm) + else TypeRef.withSym(this, sym.asType).reduceProjection // ----- Access to parts -------------------------------------------- @@ -1975,7 +1980,7 @@ object Types { def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType = designator match { case designator: TermSymbol => - TermRef.withFixedSym(prefix, designator) + TermRef(prefix, designator) case designator: TermName => // If symbol exists, the new signature is the symbol's signature as seen // from the new prefix, modulo consistency @@ -2027,12 +2032,12 @@ object Types { def apply(prefix: Type, designator: Name)(implicit ctx: Context) = if (designator.isTermName) TermRef(prefix, designator.asTermName) else TypeRef(prefix, designator.asTypeName) + def apply(prefix: Type, sym: Symbol)(implicit ctx: Context) = + if (sym.isType) TypeRef(prefix, sym.asType) + else TermRef(prefix, sym.asTerm) 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 withFixedSym(prefix: Type, sym: Symbol)(implicit ctx: Context) = - if (sym.isType) TypeRef.withFixedSym(prefix, sym.asType) - else TermRef.withFixedSym(prefix, sym.asTerm) def withSymAndName(prefix: Type, sym: Symbol, name: Name)(implicit ctx: Context): NamedType = if (sym.isType) TypeRef.withSymAndName(prefix, sym.asType, name.asTypeName) else TermRef.withSymAndName(prefix, sym.asTerm, name.asTermName) @@ -2046,14 +2051,14 @@ object Types { * Its meaning is the (potentially multi-) denotation of the member(s) * of prefix with given name. */ - def apply(prefix: Type, designator: TermName)(implicit ctx: Context): TermRef = + def apply(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] /** Create term ref referring to given symbol, taking the signature * from the symbol if it is completed, or creating a term ref without * signature, if symbol is not yet completed. */ - def apply(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = + def withSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = withSymAndName(prefix, sym, sym.name) /** Create term ref to given initial denotation, taking the signature @@ -2062,19 +2067,13 @@ object Types { */ def apply(prefix: Type, designator: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) - apply(prefix, denot.symbol.asTerm) + withSym(prefix, denot.symbol.asTerm) else denot match { case denot: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) case _ => apply(prefix, designator) } } withDenot denot - /** Create a non-member term ref (which cannot be reloaded using `member`), - * with given prefix, name, and signature - */ - def withFixedSym(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = true).asInstanceOf[TermRef] - /** Create a term ref referring to given symbol with given name, taking the signature * from the symbol if it is completed, or creating a term ref without * signature, if symbol is not yet completed. This is very similar to TermRef(Type, Symbol), @@ -2084,7 +2083,7 @@ object Types { */ def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) - withFixedSym(prefix, sym) + apply(prefix, sym) else if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature).withSym(sym) // Linker note: @@ -2098,7 +2097,7 @@ object Types { * (which must be completed). */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) withFixedSym(prefix, sym) + if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) apply(prefix, sym) else withSig(prefix, sym.name, sym.signature).withSym(sym) /** Create a term ref with given prefix, name and signature */ @@ -2108,7 +2107,7 @@ object Types { /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) - withFixedSym(prefix, denot.symbol.asTerm) + apply(prefix, denot.symbol.asTerm) else withSig(prefix, name, sig) } withDenot denot @@ -2120,15 +2119,9 @@ object Types { ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] /** Create type ref to given symbol */ - def apply(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = + def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = withSymAndName(prefix, sym, sym.name) - /** Create a non-member type ref (which cannot be reloaded using `member`), - * with given prefix, name, and symbol. - */ - def withFixedSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - ctx.uniqueNamedTypes.enterIfNew(prefix, sym, isTerm = false).asInstanceOf[TypeRef] - /** Create a type ref referring to given symbol with given name. * This is very similar to TypeRef(Type, Symbol), * except for two differences: @@ -2136,12 +2129,12 @@ object Types { * (2) The name in the type ref need not be the same as the name of the Symbol. */ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = - if ((prefix eq NoPrefix) || sym.isFresh) withFixedSym(prefix, sym) + if ((prefix eq NoPrefix) || sym.isFresh) apply(prefix, sym) else apply(prefix, name).withSym(sym) /** 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.isFresh) apply(prefix, denot.symbol.asType) + if ((prefix eq NoPrefix) || denot.symbol.isFresh) withSym(prefix, denot.symbol.asType) else apply(prefix, name) } withDenot denot } @@ -3420,7 +3413,7 @@ object Types { def clsDenot = if (prefix eq cls.owner.thisType) cls.denot else cls.denot.copySymDenotation(info = this) if (appliedRefCache == null) { val tref = - if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef + if ((cls is PackageClass) || cls.owner.isTerm) symbolicTypeRef // ??? not always symbolicRef else TypeRef(prefix, cls.name, clsDenot) appliedRefCache = tref.appliedTo(cls.typeParams.map(_.typeRef)) @@ -3428,7 +3421,7 @@ object Types { appliedRefCache } - def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef(prefix, cls) + def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef.withSym(prefix, cls) // cached because baseType needs parents private[this] var parentsCache: List[Type] = null @@ -3493,7 +3486,7 @@ object Types { case tp: ClassInfo => // Note: Taking a normal typeRef does not work here. A normal ref might contain // also other information about the named type (e.g. bounds). - contains(tp.symbolicTypeRef) + contains(tp.symbolicTypeRef) // ??? not clear case _ => lo <:< tp && tp <:< hi } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 6d2dbcfdaed5..49fd4c0f49fd 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -246,7 +246,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val sym = ctx.newSymbol(ctx.owner, readName().toTypeName, BindDefinedType, readType()) registerSym(start, sym) if (currentAddr != end) readType() - TypeRef.withFixedSym(NoPrefix, sym) + TypeRef(NoPrefix, sym) case POLYtype => readMethodic(PolyType, _.toTypeName) case METHODtype => @@ -268,7 +268,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi def readSimpleType(): Type = (tag: @switch) match { case TYPEREFdirect | TERMREFdirect => - NamedType.withFixedSym(NoPrefix, readSymRef()) + NamedType(NoPrefix, readSymRef()) case TYPEREFsymbol | TERMREFsymbol => readSymNameRef() case TYPEREFpkg => diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 2ee3f09f9aca..df26650035df 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -735,7 +735,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val tycon = if (sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package)) // used fixed sym for Scala 2 inner classes, because they might be shadowed - TypeRef.withFixedSym(pre, sym.asType) + TypeRef(pre, sym.asType) else if (isLocal(sym) || pre == NoPrefix) { val pre1 = if ((pre eq NoPrefix) && (sym is TypeParam)) sym.owner.thisType else pre pre1 select sym diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 4d2a6c454644..ef839ea82578 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 { case _ => sym.name } untpd.cpy.Select(tree)(qual, sym.name) - .withType(NamedType.withFixedSym(qual.tpe, sym)) + .withType(NamedType(qual.tpe, sym)) } def selectArrayMember(qual: Tree, erasedPre: Type): Tree = diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 52aa089fca9f..92a1450117fc 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -321,7 +321,7 @@ object ExplicitOuter { */ private def fixThis(tpe: Type)(implicit ctx: Context): Type = tpe match { case tpe: ThisType if tpe.cls.is(Module) && !ctx.owner.isContainedIn(tpe.cls) => - fixThis(TermRef(tpe.cls.owner.thisType, tpe.cls.sourceModule.asTerm)) + fixThis(TermRef.withSym(tpe.cls.owner.thisType, tpe.cls.sourceModule.asTerm)) case tpe: TermRef => tpe.derivedSelect(fixThis(tpe.prefix)) case _ => diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index ab94fe60e3d8..b63833468660 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -17,7 +17,7 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: lazy val JUnit4Annotations: List[Symbol] = List("Test", "Ignore", "Before", "After", "BeforeClass", "AfterClass"). map(n => ctx.getClassIfDefined("org.junit." + n)). filter(_.exists) - + def implementation(member: TermSymbol): TermSymbol = { val res = member.copy( owner = cls, @@ -35,7 +35,7 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: Super(This(cls), target.owner.name.asTypeName, false, target.owner) //println(i"super ref $target on $sup") ast.untpd.Select(sup.withPos(pos), target.name) - .withType(NamedType.withFixedSym(sup.tpe, target)) + .withType(NamedType(sup.tpe, target)) //sup.select(target) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index acbb1298d542..934c2236b014 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -384,7 +384,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(prefix, companion.asTerm))) + if (prefix.exists) selectGetter(ref(TermRef.withSym(prefix, companion.asTerm))) else EmptyTree } else EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 54d9dd78939d..6fb1a3259f57 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1008,7 +1008,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(pre, sym)) + f(TermRef.withSym(pre, sym)) } @sharable object EmptyTermRefSet extends TermRefSet()(NoContext) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index ba9d3f17ebdd..214c8486b8df 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -325,7 +325,7 @@ class Namer { typer: Typer => privateWithinClass(tree.mods), tree.namePos), tree) case tree: Import => recordSym(ctx.newSymbol( - ctx.owner, nme.IMPORT, Synthetic, new Completer(tree), NoSymbol, tree.pos), tree) + ctx.owner, nme.IMPORT, Synthetic | Fresh, new Completer(tree), NoSymbol, tree.pos), tree) case _ => NoSymbol } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index c7eaa5bc1e6a..c8f635b07c25 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -506,7 +506,7 @@ trait TypeAssigner { else inSameUniverse(TypeBounds(_, _), lo.tpe, hi, "type bounds")) def assignType(tree: untpd.Bind, sym: Symbol)(implicit ctx: Context) = - tree.withType(NamedType.withFixedSym(NoPrefix, sym)) + tree.withType(NamedType(NoPrefix, sym)) def assignType(tree: untpd.Alternative, trees: List[Tree])(implicit ctx: Context) = tree.withType(ctx.typeComparer.lub(trees.tpes)) @@ -532,7 +532,7 @@ trait TypeAssigner { // 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) + NamedType(owner.thisType, sym) else NoType } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 1089076f60cb..dce8496f2f5d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -989,7 +989,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit else if (!owner.isCompleted) (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos)) else { - val from = Ident(TermRef(NoPrefix, owner.asTerm)) + val from = Ident(TermRef.withSym(NoPrefix, owner.asTerm)) val proto = returnProto(owner, cx.scope) (from, proto) } From b82b2fa6da6babff49c9eb08e1dee295bacb77f8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Sep 2017 10:28:46 +0200 Subject: [PATCH 134/146] Drop nonMemberTermRef Make nonMemberTermRef redundant by marking local dummies and import symbols as Fresh (i.e. they are non-members). --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 3 --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 8 ++++++-- .../src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 3 +-- compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 6 +++--- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index e2fbe20591fa..fedfb67a1b9c 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -243,7 +243,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val localDummy = ((NoSymbol: Symbol) /: body)(findLocalDummy.apply) .orElse(ctx.newLocalDummy(cls)) val impl = untpd.Template(constr, parents, selfType, newTypeParams ++ body) - .withType(localDummy.nonMemberTermRef) + .withType(localDummy.termRef) ta.assignType(untpd.TypeDef(cls.name, impl), cls) } diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 3109a5eb8a6a..e01a0475e9b7 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1135,9 +1135,6 @@ object SymDenotations { override def termRefWithSig(implicit ctx: Context): TermRef = TermRef.withSigAndDenot(owner.thisType, name.asTermName, signature, this) - def nonMemberTermRef(implicit ctx: Context): TermRef = - TermRef(owner.thisType, symbol.asTerm) - /** The variance of this type parameter or type member as an Int, with * +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter */ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 2f3d42a826dd..ef90635e4193 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -249,8 +249,12 @@ trait Symbols { this: Context => newSymbol(cls, nme.localDummyName(cls), Fresh, NoType) /** Create an import symbol pointing back to given qualifier `expr`. */ - def newImportSymbol(owner: Symbol, expr: Tree, coord: Coord = NoCoord) = - newSymbol(owner, nme.IMPORT, EmptyFlags, ImportType(expr), coord = coord) + def newImportSymbol(owner: Symbol, expr: Tree, coord: Coord = NoCoord): TermSymbol = + newImportSymbol(owner, ImportType(expr), coord = coord) + + /** Create an import symbol with given `info`. */ + def newImportSymbol(owner: Symbol, info: Type, coord: Coord): TermSymbol = + newSymbol(owner, nme.IMPORT, Synthetic | Fresh, info, coord = coord) /** Create a class constructor symbol for given class `cls`. */ def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) = diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 49fd4c0f49fd..752bfff04c25 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -753,7 +753,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi }) setPos(start, untpd.Template(constr, parents, self, lazyStats) - .withType(localDummy.nonMemberTermRef)) + .withType(localDummy.termRef)) } def skipToplevel()(implicit ctx: Context): Unit= { diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 214c8486b8df..875236a4a10e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -324,8 +324,7 @@ class Namer { typer: Typer => adjustIfModule(completer, tree), privateWithinClass(tree.mods), tree.namePos), tree) case tree: Import => - recordSym(ctx.newSymbol( - ctx.owner, nme.IMPORT, Synthetic | Fresh, new Completer(tree), NoSymbol, tree.pos), tree) + recordSym(ctx.newImportSymbol(ctx.owner, new Completer(tree), tree.pos), tree) case _ => NoSymbol } diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index c8f635b07c25..11ad12c5cbc2 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -523,12 +523,12 @@ trait TypeAssigner { def assignType(tree: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) = tree.withType(symbolicIfNeeded(sym).orElse(sym.typeRef)) - private def symbolicIfNeeded(sym: Symbol)(implicit ctx: Context) = { + private def symbolicIfNeeded(sym: Symbol)(implicit ctx: Context) = { // ??? can we drop this? val owner = sym.owner 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 + // symbolic. In general it seems to be faster to keep the non-symbolic // 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. @@ -539,7 +539,7 @@ trait TypeAssigner { def assertExists(tp: Type) = { assert(tp != NoType); tp } def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) = - tree.withType(sym.nonMemberTermRef) + tree.withType(sym.termRef) def assignType(tree: untpd.Annotated, arg: Tree, annot: Tree)(implicit ctx: Context) = tree.withType(AnnotatedType(arg.tpe.widen, Annotation(annot))) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index dce8496f2f5d..a4f3528a0009 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1410,7 +1410,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit checkNoDoubleDefs(cls) val impl1 = cpy.Template(impl)(constr1, parents1, self1, body1) - .withType(dummy.nonMemberTermRef) + .withType(dummy.termRef) checkVariance(impl1) if (!cls.is(AbstractOrTrait) && !ctx.isAfterTyper) checkRealizableBounds(cls, cdef.namePos) From df0057c6bc9e0715cdf4939a57938d4028abbdd8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Sep 2017 10:31:41 +0200 Subject: [PATCH 135/146] Drop Fresh in mapSymbols --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index ef90635e4193..887a5c7b94ec 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -348,7 +348,7 @@ trait Symbols { this: Context => copy.denot = odenot.copySymDenotation( symbol = copy, owner = ttmap1.mapOwner(odenot.owner), - initFlags = odenot.flags &~ Touched | Fresh, + initFlags = odenot.flags &~ Touched,// | Fresh, info = completer, privateWithin = ttmap1.mapOwner(odenot.privateWithin), // since this refers to outer symbols, need not include copies (from->to) in ownermap here. annotations = odenot.annotations) From 1ec7fe57e05fe0f05d9aadb2b83179fbc78a8ee3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Sep 2017 13:50:11 +0200 Subject: [PATCH 136/146] Use a general criterion for when to refer to symbols symbolically Also - rename Fresh flag to NonMember - update criterion for phases where refs are symbolic. This used to be just before erasure (at resolveSuper) but then other phases were inserted after resolveSuper and the test became outdated. It's more robust now. --- compiler/src/dotty/tools/dotc/core/Flags.scala | 6 +++--- compiler/src/dotty/tools/dotc/core/Phases.scala | 2 +- .../src/dotty/tools/dotc/core/Symbols.scala | 16 +++++++++++----- compiler/src/dotty/tools/dotc/core/Types.scala | 17 ++++++----------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 175fe3acc115..b5f9517250c1 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -359,8 +359,8 @@ object Flags { // Flags following this one are not pickled - /** Symbol always defines a fresh named type */ - final val Fresh = commonFlag(45, "") + /** Symbol is not a member of its owner */ + final val NonMember = commonFlag(45, "") /** Denotation is in train of being loaded and completed, used to catch cyclic dependencies */ final val Touched = commonFlag(48, "") @@ -446,7 +446,7 @@ object Flags { Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor.toCommonFlags | Scala2ExistentialCommon | Mutable.toCommonFlags | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | CaseAccessor.toCommonFlags | - Fresh | Erroneous | ImplicitCommon | Permanent | Synthetic | + NonMember | Erroneous | ImplicitCommon | Permanent | Synthetic | SuperAccessorOrScala2x | Inline /** Flags guaranteed to be set upon symbol creation, or, if symbol is a top-level diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 0312f94f4533..7117647426bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -359,7 +359,7 @@ object Phases { myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked - mySymbolicRefs = prev.getClass == classOf[ResolveSuper] || prev.symbolicRefs + 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/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 887a5c7b94ec..aa464a8042b0 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -246,7 +246,7 @@ trait Symbols { this: Context => * would be `fld2`. There is a single local dummy per template. */ def newLocalDummy(cls: Symbol, coord: Coord = NoCoord) = - newSymbol(cls, nme.localDummyName(cls), Fresh, NoType) + newSymbol(cls, nme.localDummyName(cls), NonMember, NoType) /** Create an import symbol pointing back to given qualifier `expr`. */ def newImportSymbol(owner: Symbol, expr: Tree, coord: Coord = NoCoord): TermSymbol = @@ -254,7 +254,7 @@ trait Symbols { this: Context => /** Create an import symbol with given `info`. */ def newImportSymbol(owner: Symbol, info: Type, coord: Coord): TermSymbol = - newSymbol(owner, nme.IMPORT, Synthetic | Fresh, info, coord = coord) + newSymbol(owner, nme.IMPORT, Synthetic | NonMember, info, coord = coord) /** Create a class constructor symbol for given class `cls`. */ def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) = @@ -348,7 +348,7 @@ trait Symbols { this: Context => copy.denot = odenot.copySymDenotation( symbol = copy, owner = ttmap1.mapOwner(odenot.owner), - initFlags = odenot.flags &~ Touched,// | Fresh, + initFlags = odenot.flags &~ Touched, info = completer, privateWithin = ttmap1.mapOwner(odenot.privateWithin), // since this refers to outer symbols, need not include copies (from->to) in ownermap here. annotations = odenot.annotations) @@ -447,8 +447,14 @@ object Symbols { final def isClass: Boolean = isInstanceOf[ClassSymbol] final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] - final def isFresh(implicit ctx: Context) = - lastDenot != null && (lastDenot is Fresh) + final def isReferencedSymbolically(implicit ctx: Context) = { + val sym = lastDenot + sym != null && ( + (sym is NonMember) + || sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package) + || sym.isTerm && ctx.phase.symbolicRefs + ) + } /** Special cased here, because it may be used on naked symbols in substituters */ final def isStatic(implicit ctx: Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d59418b0e576..0a57c2938169 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1123,11 +1123,6 @@ object Types { loop(this) } - private def isReferencedSymbolically(sym: Symbol)(implicit ctx: Context) = - sym.isFresh || - sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package) || - ctx.phase.symbolicRefs - /** The type , reduced if possible */ def select(name: Name)(implicit ctx: Context): Type = name match { case name: TermName => TermRef(this, name) @@ -2066,7 +2061,7 @@ object Types { * signature, if denotation is not yet completed. */ def apply(prefix: Type, designator: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { - if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically || symbolicRefs) withSym(prefix, denot.symbol.asTerm) else denot match { case denot: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) @@ -2082,7 +2077,7 @@ object Types { * (2) The name in the term ref need not be the same as the name of the Symbol. */ def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically|| symbolicRefs) apply(prefix, sym) else if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature).withSym(sym) @@ -2097,7 +2092,7 @@ object Types { * (which must be completed). */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isFresh || symbolicRefs) apply(prefix, sym) + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically || symbolicRefs) apply(prefix, sym) else withSig(prefix, sym.name, sym.signature).withSym(sym) /** Create a term ref with given prefix, name and signature */ @@ -2106,7 +2101,7 @@ object Types { /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { - if ((prefix eq NoPrefix) || denot.symbol.isFresh || symbolicRefs) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically || symbolicRefs) apply(prefix, denot.symbol.asTerm) else withSig(prefix, name, sig) @@ -2129,12 +2124,12 @@ object Types { * (2) The name in the type ref need not be the same as the name of the Symbol. */ def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = - if ((prefix eq NoPrefix) || sym.isFresh) apply(prefix, sym) + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) else apply(prefix, name).withSym(sym) /** 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.isFresh) withSym(prefix, denot.symbol.asType) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) withSym(prefix, denot.symbol.asType) else apply(prefix, name) } withDenot denot } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 752bfff04c25..fe87f4d83273 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -981,7 +981,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi UnApply(fn, implicitArgs, argPats, patType) case REFINEDtpt => val refineCls = ctx.newCompleteClassSymbol( - ctx.owner, tpnme.REFINE_CLASS, Fresh, parents = Nil) + ctx.owner, tpnme.REFINE_CLASS, NonMember, parents = Nil) typeAtAddr(start) = refineCls.typeRef val parent = readTpt() val refinements = readStats(refineCls, end)(localContext(refineCls)) From 483a8f315d9df51de5e22dcd4bf6d0b28ae206d1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 12 Sep 2017 18:14:16 +0200 Subject: [PATCH 137/146] Streamline NamedType creation methods - drop withSym - rename withSymAndName to another apply - streamline select methods --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 4 +- .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../tools/dotc/core/SymDenotations.scala | 8 +- .../src/dotty/tools/dotc/core/Symbols.scala | 22 ++-- .../dotty/tools/dotc/core/TypeErasure.scala | 2 +- .../src/dotty/tools/dotc/core/Types.scala | 100 +++++++----------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 2 +- .../tools/dotc/transform/ExplicitOuter.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 3 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- 11 files changed, 66 insertions(+), 83 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index fedfb67a1b9c..c8c19f95311d 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -97,8 +97,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Closure(meth: TermSymbol, rhsFn: List[List[Tree]] => Tree, targs: List[Tree] = Nil, targetType: Type = NoType)(implicit ctx: Context): Block = { val targetTpt = if (targetType.exists) TypeTree(targetType) else EmptyTree val call = - if (targs.isEmpty) Ident(TermRef.withSym(NoPrefix, meth)) - else TypeApply(Ident(TermRef.withSym(NoPrefix, meth)), targs) + if (targs.isEmpty) Ident(TermRef(NoPrefix, meth)) + else TypeApply(Ident(TermRef(NoPrefix, meth)), targs) Block( DefDef(meth, rhsFn) :: Nil, Closure(Nil, call, targetTpt)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 0d669aab7fa8..f246dc1a165a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -174,7 +174,7 @@ class Definitions { lazy val RootClass: ClassSymbol = ctx.newPackageSymbol( NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass lazy val RootPackage: TermSymbol = ctx.newSymbol( - NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef.withSym(NoPrefix, RootClass)) + NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass)) lazy val EmptyPackageVal = ctx.newPackageSymbol( RootClass, nme.EMPTY_PACKAGE, (emptypkg, emptycls) => ctx.rootLoader(emptypkg)).entered diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index e01a0475e9b7..b947168efe36 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -1398,9 +1398,11 @@ object SymDenotations { myThisType } - private def computeThisType(implicit ctx: Context): Type = - ThisType.raw(TypeRef.withSym( - if (this is Package) NoPrefix else owner.thisType, symbol.asType)) + private def computeThisType(implicit ctx: Context): Type = { + val cls = symbol.asType + val pre = if (this is Package) NoPrefix else owner.thisType + ThisType.raw(TypeRef(pre, cls, cls.name)) + } private[this] var myTypeRef: TypeRef = null diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index aa464a8042b0..3285178ed765 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -154,7 +154,7 @@ trait Symbols { this: Context => infoFn(module, modcls), privateWithin) val mdenot = SymDenotation( module, owner, name, modFlags | ModuleCreationFlags, - if (cdenot.isCompleted) TypeRef.withSymAndName(owner.thisType, modcls, modclsName) + if (cdenot.isCompleted) TypeRef(owner.thisType, modcls, modclsName) else new ModuleCompleter(modcls)) module.denot = mdenot modcls.denot = cdenot @@ -179,7 +179,7 @@ trait Symbols { this: Context => newModuleSymbol( owner, name, modFlags, clsFlags, (module, modcls) => ClassInfo( - owner.thisType, modcls, parents, decls, TermRef.withSymAndName(owner.thisType, module, name)), + owner.thisType, modcls, parents, decls, TermRef(owner.thisType, module, name)), privateWithin, coord, assocFile) val companionMethodFlags = Flags.Synthetic | Flags.Private | Flags.Method @@ -287,7 +287,7 @@ trait Symbols { this: Context => for (name <- names) { val tparam = newNakedSymbol[TypeName](NoCoord) tparamBuf += tparam - trefBuf += TypeRef.withSymAndName(owner.thisType, tparam, name) + trefBuf += TypeRef(owner.thisType, tparam, name) } val tparams = tparamBuf.toList val bounds = boundsFn(trefBuf.toList) @@ -443,19 +443,23 @@ object Symbols { asInstanceOf[TypeSymbol] } - final def isClass: Boolean = isInstanceOf[ClassSymbol] final def asClass: ClassSymbol = asInstanceOf[ClassSymbol] final def isReferencedSymbolically(implicit ctx: Context) = { - val sym = lastDenot - sym != null && ( - (sym is NonMember) - || sym.isClass && sym.is(Scala2x) && !sym.owner.is(Package) - || sym.isTerm && ctx.phase.symbolicRefs + val d = lastDenot + d != null && ( + (d is NonMember) + || d.isClass && d.is(Scala2x) && !d.owner.is(Package) + || d.isTerm && ctx.phase.symbolicRefs ) } + /** The symbol's signature if it is completed, NotAMethod otherwise. */ + final def unforcedSignature(implicit ctx: Context) = + if (lastDenot != null && lastDenot.isCompleted) lastDenot.signature + else Signature.NotAMethod + /** Special cased here, because it may be used on naked symbols in substituters */ final def isStatic(implicit ctx: Context): Boolean = lastDenot != null && denot.isStatic diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 640539246b38..18c58ba6b456 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -150,7 +150,7 @@ object TypeErasure { assert(tp.symbol.exists, tp) val tp1 = ctx.makePackageObjPrefixExplicit(tp) if (tp1 ne tp) erasedRef(tp1) - else TermRef.withSym(erasedRef(tp.prefix), tp.symbol.asTerm) + else TermRef(erasedRef(tp.prefix), tp.symbol.asTerm) case tp: ThisType => tp case tp => diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 0a57c2938169..c1e9a1f3424b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1124,21 +1124,16 @@ object Types { } /** The type , reduced if possible */ - def select(name: Name)(implicit ctx: Context): Type = name match { - case name: TermName => TermRef(this, name) - case name: TypeName => TypeRef(this, name).reduceProjection - } + def select(name: Name)(implicit ctx: Context): Type = + NamedType(this, name).reduceProjection /** The type , reduced if possible, with given denotation if unreduced */ - def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = name match { - case name: TermName => TermRef(this, name, denot) - case name: TypeName => TypeRef(this, name, denot).reduceProjection - } + def select(name: Name, denot: Denotation)(implicit ctx: Context): Type = + NamedType(this, name, denot).reduceProjection - /** The type with given symbol, reduced if possible */ + /** The type with either `sym` or its signed name as designator, reduced if possible */ def select(sym: Symbol)(implicit ctx: Context): Type = - if (sym.isTerm) TermRef.withSym(this, sym.asTerm) - else TypeRef.withSym(this, sym.asType).reduceProjection + NamedType(this, sym, sym.name).reduceProjection // ----- Access to parts -------------------------------------------- @@ -1762,10 +1757,12 @@ object Types { * provided `U` does not refer with a RecThis to the * refinement type `T { X = U; ... }` */ - def reduceProjection(implicit ctx: Context): Type = { - val reduced = prefix.lookupRefined(name) - if (reduced.exists) reduced else this - } + def reduceProjection(implicit ctx: Context): Type = + if (isType) { + val reduced = prefix.lookupRefined(name) + if (reduced.exists) reduced else this + } + else this def symbol(implicit ctx: Context): Symbol = if (checkedPeriod == ctx.period || @@ -2033,15 +2030,13 @@ object Types { 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 withSymAndName(prefix: Type, sym: Symbol, name: Name)(implicit ctx: Context): NamedType = - if (sym.isType) TypeRef.withSymAndName(prefix, sym.asType, name.asTypeName) - else TermRef.withSymAndName(prefix, sym.asTerm, name.asTermName) + def apply(prefix: Type, sym: Symbol, name: Name)(implicit ctx: Context): NamedType = + if (sym.isType) TypeRef.apply(prefix, sym.asType, name.asTypeName) + else TermRef.apply(prefix, sym.asTerm, name.asTermName) } object TermRef { - private def symbolicRefs(implicit ctx: Context) = ctx.phase.symbolicRefs - /** 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. @@ -2049,59 +2044,44 @@ object Types { def apply(prefix: Type, designator: TermDesignator)(implicit ctx: Context): TermRef = ctx.uniqueNamedTypes.enterIfNew(prefix, designator, isTerm = true).asInstanceOf[TermRef] - /** Create term ref referring to given symbol, taking the signature - * from the symbol if it is completed, or creating a term ref without - * signature, if symbol is not yet completed. + /** 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)(implicit ctx: Context): TermRef = - withSymAndName(prefix, sym, sym.name) + def apply(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) + apply(prefix, sym) + else + withSig(prefix, name.asTermName, sym.unforcedSignature).withSym(sym) /** Create term ref to given initial denotation, taking the signature * from the denotation if it is completed, or creating a term ref without * signature, if denotation is not yet completed. */ def apply(prefix: Type, designator: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically || symbolicRefs) - withSym(prefix, denot.symbol.asTerm) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) + apply(prefix, denot.symbol.asTerm) else denot match { case denot: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) case _ => apply(prefix, designator) } } withDenot denot - /** Create a term ref referring to given symbol with given name, taking the signature - * from the symbol if it is completed, or creating a term ref without - * signature, if symbol is not yet completed. This is very similar to TermRef(Type, Symbol), - * except for two differences: - * (1) The symbol might not yet have a denotation, so the name needs to be given explicitly. - * (2) The name in the term ref need not be the same as the name of the Symbol. - */ - def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically|| symbolicRefs) - apply(prefix, sym) - else if (sym.defRunId != NoRunId && sym.isCompleted) - withSig(prefix, name, sym.signature).withSym(sym) - // Linker note: - // this is problematic, as withSig method could return a hash-consed refference - // that could have symbol already set making withSym trigger a double-binding error - // ./tests/run/absoverride.scala demonstates this - else - withSig(prefix, name, Signature.NotAMethod).withSym(sym) - /** Create a term ref to given symbol, taking the signature from the symbol * (which must be completed). */ def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically || symbolicRefs) apply(prefix, sym) + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) else withSig(prefix, sym.name, sym.signature).withSym(sym) /** Create a term ref with given prefix, name and signature */ - def withSig(prefix: Type, designator: TermName, sig: Signature)(implicit ctx: Context): TermRef = - apply(prefix, designator.withSig(sig)) + def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef = + apply(prefix, name.withSig(sig)) /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { - if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically || symbolicRefs) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) else withSig(prefix, name, sig) @@ -2109,27 +2089,23 @@ object Types { } object TypeRef { + /** Create type ref with given prefix and name */ def apply(prefix: Type, desig: TypeDesignator)(implicit ctx: Context): TypeRef = ctx.uniqueNamedTypes.enterIfNew(prefix, desig, isTerm = false).asInstanceOf[TypeRef] - /** Create type ref to given symbol */ - def withSym(prefix: Type, sym: TypeSymbol)(implicit ctx: Context): TypeRef = - withSymAndName(prefix, sym, sym.name) - - /** Create a type ref referring to given symbol with given name. - * This is very similar to TypeRef(Type, Symbol), - * except for two differences: - * (1) The symbol might not yet have a denotation, so the name needs to be given explicitly. - * (2) The name in the type ref need not be the same as the name of the Symbol. + /** Create a type ref referring to either a given symbol or its name. + * This is similar to TypeRef(prefix, sym), except: + * (1) the symbol might not yet have a denotation, so the name needs to be given explicitly. + * (2) the designator of the TypeRef is either the symbol or its name */ - def withSymAndName(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = + def apply(prefix: Type, sym: TypeSymbol, name: TypeName)(implicit ctx: Context): TypeRef = if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) else apply(prefix, name).withSym(sym) /** 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) withSym(prefix, denot.symbol.asType) + if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asType) else apply(prefix, name) } withDenot denot } @@ -3416,7 +3392,7 @@ object Types { appliedRefCache } - def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef.withSym(prefix, cls) + def symbolicTypeRef(implicit ctx: Context): TypeRef = TypeRef(prefix, cls, cls.name) // cached because baseType needs parents private[this] var parentsCache: List[Type] = null diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index fe87f4d83273..c03cd08e3258 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -330,7 +330,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.withSymAndName(prefix, sym, sym.name) + val res = NamedType(prefix, sym, sym.name) prefix match { case prefix: ThisType if prefix.cls eq sym.owner => res.withDenot(sym.denot) // without this precaution we get an infinite cycle when unpickling pos/extmethods.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 92a1450117fc..2b10d7341280 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -321,7 +321,7 @@ object ExplicitOuter { */ private def fixThis(tpe: Type)(implicit ctx: Context): Type = tpe match { case tpe: ThisType if tpe.cls.is(Module) && !ctx.owner.isContainedIn(tpe.cls) => - fixThis(TermRef.withSym(tpe.cls.owner.thisType, tpe.cls.sourceModule.asTerm)) + fixThis(tpe.cls.owner.thisType.select(tpe.cls.sourceModule.asTerm)) case tpe: TermRef => tpe.derivedSelect(fixThis(tpe.prefix)) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 934c2236b014..302c3768e6fb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -384,7 +384,8 @@ 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, companion.name.asTermName))) else EmptyTree } else EmptyTree diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6fb1a3259f57..d0017c01cd30 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1008,7 +1008,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, sym.name)) } @sharable object EmptyTermRefSet extends TermRefSet()(NoContext) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a4f3528a0009..d82a00739ec3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -989,7 +989,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit else if (!owner.isCompleted) (EmptyTree, errorType(MissingReturnTypeWithReturnStatement(owner), tree.pos)) else { - val from = Ident(TermRef.withSym(NoPrefix, owner.asTerm)) + val from = Ident(TermRef(NoPrefix, owner.asTerm)) val proto = returnProto(owner, cx.scope) (from, proto) } From 760479b38dbaa192fe6110a5f932220c897127ba Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 13 Sep 2017 09:08:52 +0200 Subject: [PATCH 138/146] Eliminate TermRef.withSig To do this, we needed a more robust version of Symbol#signature. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 12 +++---- .../src/dotty/tools/dotc/core/Symbols.scala | 10 +++--- .../src/dotty/tools/dotc/core/Types.scala | 36 ++++++++----------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 4 +-- .../core/unpickleScala2/Scala2Unpickler.scala | 4 +-- .../dotc/transform/ParamForwarding.scala | 4 +-- .../tools/dotc/transform/PostTyper.scala | 2 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- 8 files changed, 34 insertions(+), 40 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index c8c19f95311d..20bd2775560d 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -6,7 +6,7 @@ import dotty.tools.dotc.transform.{ExplicitOuter, Erasure} import dotty.tools.dotc.typer.ProtoTypes.FunProtoTyped import transform.SymUtils._ import core._ -import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ +import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._ import Denotations._, Decorators._, DenotTransformers._ import collection.mutable @@ -382,7 +382,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { val targs = tp.argTypes val tycon = tp.typeConstructor New(tycon) - .select(TermRef.withSig(tycon, constr)) + .select(TermRef(tycon, constr, constr.name)) .appliedToTypes(targs) .appliedToArgs(args) } @@ -704,14 +704,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { else TermRef.withSigAndDenot(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe)) - untpd.Select(tree, sym.name) - .withType(tp) + untpd.Select(tree, sym.name).withType(tp) } /** 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.withSig(tree.tpe, name.asTermName, sig)) + .withType(TermRef(tree.tpe, name.asTermName.withSig(sig))) /** A select node with selector name and signature taken from `sym`. * Note: Use this method instead of select(sym) if the referenced symbol @@ -918,8 +917,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { alternatives.head } else denot.asSingleDenotation.termRef + val selectedSym = selected.termSymbol.asTerm val fun = receiver - .select(TermRef.withSig(receiver.tpe, selected.termSymbol.asTerm)) + .select(TermRef(receiver.tpe, selectedSym, selectedSym.name)) .appliedToTypes(targs) def adaptLastArg(lastParam: Tree, expectedType: Type) = { diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 3285178ed765..71bd7708cd70 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -455,10 +455,12 @@ object Symbols { ) } - /** The symbol's signature if it is completed, NotAMethod otherwise. */ - final def unforcedSignature(implicit ctx: Context) = - if (lastDenot != null && lastDenot.isCompleted) lastDenot.signature - else Signature.NotAMethod + /** The symbol's signature if it is completed or a method, NotAMethod otherwise. */ + final def signature(implicit ctx: Context) = + if (lastDenot != null && (lastDenot.isCompleted || lastDenot.is(Method))) + denot.signature + else + Signature.NotAMethod /** Special cased here, because it may be used on naked symbols in substituters */ final def isStatic(implicit ctx: Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index c1e9a1f3424b..e0470adcd8d8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -707,7 +707,10 @@ 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.withSig(this, d.symbol.asTerm)) + .toList.map { d => + val mbr = d.symbol.asTerm + TermRef(this, mbr, mbr.name) + } } /** The set of member classes of this type */ @@ -1729,7 +1732,7 @@ object Types { } private def withSig(sig: Signature)(implicit ctx: Context): NamedType = - TermRef.withSig(prefix, name.asTermName, sig) + TermRef(prefix, name.asTermName.withSig(sig)) protected def loadDenot(implicit ctx: Context): Denotation = { val d = asMemberOf(prefix, allowPrivate = true) @@ -1985,7 +1988,7 @@ object Types { val candidate = if (newSig ne curSig) { core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $curSig --> $newSig") - TermRef.withSig(prefix, name, newSig) + TermRef(prefix, name.withSig(newSig)) } else TermRef(prefix, designator) fixDenot(candidate, prefix) @@ -2050,41 +2053,30 @@ object Types { * (2) the designator of the TermRef is either the symbol or its name & unforced signature. */ def apply(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) - apply(prefix, sym) - else - withSig(prefix, name.asTermName, sym.unforcedSignature).withSym(sym) + if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) + else apply(prefix, name.withSig(sym.signature)).withSym(sym) /** Create term ref to given initial denotation, taking the signature * from the denotation if it is completed, or creating a term ref without * signature, if denotation is not yet completed. */ - def apply(prefix: Type, designator: TermName, denot: Denotation)(implicit ctx: Context): TermRef = { + 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: SymDenotation if denot.isCompleted => withSig(prefix, designator, denot.signature) - case _ => apply(prefix, designator) + case denot: SymDenotation if denot.isCompleted => + apply(prefix, name.withSig(denot.signature)) + case _ => + apply(prefix, name) } } withDenot denot - /** Create a term ref to given symbol, taking the signature from the symbol - * (which must be completed). - */ - def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = - if ((prefix eq NoPrefix) || sym.isReferencedSymbolically) apply(prefix, sym) - else withSig(prefix, sym.name, sym.signature).withSym(sym) - - /** Create a term ref with given prefix, name and signature */ - def withSig(prefix: Type, name: TermName, sig: Signature)(implicit ctx: Context): TermRef = - apply(prefix, name.withSig(sig)) - /** Create a term ref with given prefix, name, signature, and initial denotation */ def withSigAndDenot(prefix: Type, name: TermName, sig: Signature, denot: Denotation)(implicit ctx: Context): TermRef = { if ((prefix eq NoPrefix) || denot.symbol.isReferencedSymbolically) apply(prefix, denot.symbol.asTerm) else - withSig(prefix, name, sig) + apply(prefix, name.withSig(sig)) } withDenot denot } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index c03cd08e3258..06bb090b18e1 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -710,7 +710,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi val cls = ctx.owner.asClass val assumedSelfType = if (cls.is(Module) && cls.owner.isClass) - TermRef.withSig(cls.owner.thisType, cls.name.sourceModuleName, Signature.NotAMethod) + TermRef(cls.owner.thisType, cls.name.sourceModuleName.withSig(Signature.NotAMethod)) else NoType cls.info = new TempClassInfo(cls.owner.thisType, cls, cls.unforcedDecls, assumedSelfType) val localDummy = symbolAtCurrent() @@ -871,7 +871,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi untpd.Ident(readName().toTypeName).withType(readType()) case SELECT => def readRest(name: Name, sig: Signature) = - completeSelect(name, TermRef.withSig(_, name.asTermName, sig)) + completeSelect(name, TermRef(_, name.asTermName.withSig(sig))) readName() match { case SignedName(name, sig) => readRest(name, sig) case name => readRest(name, Signature.NotAMethod) diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index df26650035df..6355c26c947d 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -704,8 +704,8 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas case SINGLEtpe => val pre = readTypeRef() val sym = readDisambiguatedSymbolRef(_.info.isParameterless) - if (isLocal(sym) || (pre == NoPrefix)) pre select sym - else TermRef.withSig(pre, sym.name.asTermName, Signature.NotAMethod) // !!! should become redundant + if (isLocal(sym) || (pre eq NoPrefix)) pre select sym + else TermRef(pre, sym.name.asTermName.withSig(Signature.NotAMethod)) // !!! should become redundant case SUPERtpe => val thistpe = readTypeRef() val supertpe = readTypeRef() diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index fe124424d033..fb1ae1cf6748 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -4,7 +4,7 @@ package transform import core._ import ast.Trees._ import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._, StdNames._ -import Decorators._ +import Decorators._, NameOps._ import config.Printers.typr /** For all parameter accessors @@ -96,7 +96,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) { // It could be a param forwarder; adapt the signature val newSig = tpe.prefix.memberInfo(tpe.symbol).signature if (newSig == Signature.NotAMethod) tree - else tree.withType(TermRef.withSig(tpe.prefix, tpe.name, newSig)).asInstanceOf[T] + else tree.withType(TermRef(tpe.prefix, tpe.name.withSig(newSig))).asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 0a5202a60080..2b383d5ad46a 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -86,7 +86,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran 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.withSig(tpe.prefix, tpe.name, tpe.widen.signature)).asInstanceOf[T] + tree.withType(TermRef(tpe.prefix, tpe.name.withSig(tpe.widen.signature))).asInstanceOf[T] case _ => tree } diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index d0017c01cd30..476a951ac810 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -428,7 +428,7 @@ trait ImplicitRunInfo { self: RunInfo => def addRef(companion: TermRef): Unit = { val compSym = companion.symbol if (compSym is Package) - addRef(TermRef.withSig(companion, nme.PACKAGE, Signature.NotAMethod)) + addRef(TermRef(companion, nme.PACKAGE.withSig(Signature.NotAMethod))) else if (compSym.exists) comps += companion.asSeenFrom(pre, compSym.owner).asInstanceOf[TermRef] } From 98d8ecfe3b6de5914d06a970c80f1beb643459d3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 13 Sep 2017 09:40:48 +0200 Subject: [PATCH 139/146] Eliminate termRefWithSig and valRef Also, drop signature parameter in TermRef.withSigAndDenot --- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- compiler/src/dotty/tools/dotc/ast/tpd.scala | 2 +- .../dotty/tools/dotc/core/Annotations.scala | 2 +- .../dotty/tools/dotc/core/Denotations.scala | 18 ++---------------- .../src/dotty/tools/dotc/core/Scopes.scala | 2 +- .../dotty/tools/dotc/core/SymDenotations.scala | 6 ------ .../src/dotty/tools/dotc/core/TypeOps.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 6 +++--- .../dotty/tools/dotc/typer/EtaExpansion.scala | 2 +- .../src/dotty/tools/dotc/typer/Implicits.scala | 2 +- .../dotty/tools/dotc/typer/ImportInfo.scala | 2 +- .../dotty/tools/dotc/typer/Inferencing.scala | 2 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 6 +++--- .../src/dotty/tools/dotc/typer/Typer.scala | 5 ++--- 14 files changed, 19 insertions(+), 40 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index d1dc727428a2..47ad30e0ea5b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1057,7 +1057,7 @@ object desugar { } else if (arity == 1) ts.head else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts) else if (arity == 0) unitLiteral - else Apply(ref(tupleTypeRef.classSymbol.companionModule.valRef), ts) + else Apply(ref(tupleTypeRef.classSymbol.companionModule.termRef), ts) case WhileDo(cond, body) => // {