diff options
7 files changed, 65 insertions, 45 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala index c647ef6f51..c5bb8494ce 100644 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala +++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala @@ -37,7 +37,7 @@ trait CompletionOutput { val pkg = method.ownerChain find (_.isPackageClass) map (_.fullName) getOrElse "" def relativize(str: String): String = quietString(str stripPrefix (pkg + ".")) - def relativize(tp: Type): String = relativize(tp.normalize.toString) + def relativize(tp: Type): String = relativize(tp.dealiasWiden.toString) def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]") def parenList(params: List[Any]) = params.mkString("(", ", ", ")") @@ -55,8 +55,8 @@ trait CompletionOutput { } ) - def tupleString(tp: Type) = parenList(tp.normalize.typeArgs map relativize) - def functionString(tp: Type) = tp.normalize.typeArgs match { + def tupleString(tp: Type) = parenList(tp.dealiasWiden.typeArgs map relativize) + def functionString(tp: Type) = tp.dealiasWiden.typeArgs match { case List(t, r) => t + " => " + r case xs => parenList(xs.init) + " => " + xs.last } @@ -64,7 +64,7 @@ trait CompletionOutput { def tparamsString(tparams: List[Symbol]) = braceList(tparams map (_.defString)) def paramsString(params: List[Symbol]) = { def paramNameString(sym: Symbol) = if (sym.isSynthetic) "" else sym.nameString + ": " - def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.normalize) + def paramString(sym: Symbol) = paramNameString(sym) + typeToString(sym.info.dealiasWiden) val isImplicit = params.nonEmpty && params.head.isImplicit val strs = (params map paramString) match { diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala index 91e909b1f1..36f012229e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala +++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala @@ -523,7 +523,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends // normalize non-public types so we don't see protected aliases like Self def normalizeNonPublic(tp: Type) = tp match { - case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.normalize + case TypeRef(_, sym, _) if sym.isAliasType && !sym.isPublic => tp.dealias case _ => tp } diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 8d6e0c3b85..ed1e6d01e8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -439,8 +439,8 @@ trait Implicits { val start = if (Statistics.canEnable) Statistics.startTimer(matchesPtNanos) else null val result = normSubType(tp, pt) || isView && { pt match { - case TypeRef(_, Function1.Sym, args) => - matchesPtView(tp, args.head, args.tail.head, undet) + case TypeRef(_, Function1.Sym, arg1 :: arg2 :: Nil) => + matchesPtView(tp, arg1, arg2, undet) case _ => false } @@ -484,7 +484,7 @@ trait Implicits { loop(restpe, pt) else pt match { case tr @ TypeRef(pre, sym, args) => - if (sym.isAliasType) loop(tp, pt.normalize) + if (sym.isAliasType) loop(tp, pt.dealias) else if (sym.isAbstractType) loop(tp, pt.bounds.lo) else { val len = args.length - 1 @@ -528,18 +528,15 @@ trait Implicits { * to a final true or false. */ private def isPlausiblySubType(tp1: Type, tp2: Type) = !isImpossibleSubType(tp1, tp2) - private def isImpossibleSubType(tp1: Type, tp2: Type) = tp1.normalize.widen match { - case tr1 @ TypeRef(_, sym1, _) => - // We can only rule out a subtype relationship if the left hand - // side is a class, else we may not know enough. - sym1.isClass && (tp2.normalize.widen match { - case TypeRef(_, sym2, _) => - sym2.isClass && !(sym1 isWeakSubClass sym2) - case RefinedType(parents, decls) => - decls.nonEmpty && - tr1.member(decls.head.name) == NoSymbol - case _ => false - }) + private def isImpossibleSubType(tp1: Type, tp2: Type) = tp1.dealiasWiden match { + // We can only rule out a subtype relationship if the left hand + // side is a class, else we may not know enough. + case tr1 @ TypeRef(_, sym1, _) if sym1.isClass => + tp2.dealiasWiden match { + case TypeRef(_, sym2, _) => sym2.isClass && !(sym1 isWeakSubClass sym2) + case RefinedType(parents, decls) => decls.nonEmpty && tr1.member(decls.head.name) == NoSymbol + case _ => false + } case _ => false } @@ -1010,7 +1007,7 @@ trait Implicits { args foreach (getParts(_)) } } else if (sym.isAliasType) { - getParts(tp.normalize) + getParts(tp.dealias) } else if (sym.isAbstractType) { getParts(tp.bounds.hi) } @@ -1168,7 +1165,7 @@ trait Implicits { implicit def wrapResult(tree: Tree): SearchResult = if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to)) - val tp1 = tp0.normalize + val tp1 = tp0.dealias tp1 match { case ThisType(_) | SingleType(_, _) => // can't generate a reference to a value that's abstracted over by an existential diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 2693fcfd27..a43dbae1fa 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -43,7 +43,7 @@ trait Infer extends Checkable { case formal => formal } else formals if (isVarArgTypes(formals1) && (removeRepeated || formals.length != nargs)) { - val ft = formals1.last.normalize.typeArgs.head + val ft = formals1.last.dealiasWiden.typeArgs.head formals1.init ::: (for (i <- List.range(formals1.length - 1, nargs)) yield ft) } else formals1 } @@ -1437,9 +1437,9 @@ trait Infer extends Checkable { } object approximateAbstracts extends TypeMap { - def apply(tp: Type): Type = tp.normalize match { + def apply(tp: Type): Type = tp.dealiasWiden match { case TypeRef(pre, sym, _) if sym.isAbstractType => WildcardType - case _ => mapOver(tp) + case _ => mapOver(tp) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index abc5baff72..b5f456d1ae 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -13,7 +13,7 @@ package scala.tools.nsc package typechecker import scala.collection.mutable -import scala.reflect.internal.util.{ BatchSourceFile, Statistics } +import scala.reflect.internal.util.{ BatchSourceFile, Statistics, shortClassOfInstance } import mutable.ListBuffer import symtab.Flags._ @@ -227,7 +227,7 @@ trait Typers extends Modes with Adaptations with Tags { case ExistentialType(tparams, tpe) => new SubstWildcardMap(tparams).apply(tp) case TypeRef(_, sym, _) if sym.isAliasType => - val tp0 = tp.normalize + val tp0 = tp.dealias val tp1 = dropExistential(tp0) if (tp1 eq tp0) tp else tp1 case _ => tp @@ -413,7 +413,7 @@ trait Typers extends Modes with Adaptations with Tags { if (!hiddenSymbols.isEmpty && hiddenSymbols.head == sym && sym.isAliasType && sameLength(sym.typeParams, args)) { hiddenSymbols = hiddenSymbols.tail - t.normalize + t.dealias } else t case SingleType(_, sym) => checkNoEscape(sym) @@ -1033,9 +1033,9 @@ trait Typers extends Modes with Adaptations with Tags { adapt(tree setType restpe, mode, pt, original) case TypeRef(_, ByNameParamClass, List(arg)) if ((mode & EXPRmode) != 0) => // (2) adapt(tree setType arg, mode, pt, original) - case tr @ TypeRef(_, sym, _) if sym.isAliasType && tr.normalize.isInstanceOf[ExistentialType] && + case tr @ TypeRef(_, sym, _) if sym.isAliasType && tr.dealias.isInstanceOf[ExistentialType] && ((mode & (EXPRmode | LHSmode)) == EXPRmode) => - adapt(tree setType tr.normalize.skolemizeExistential(context.owner, tree), mode, pt, original) + adapt(tree setType tr.dealias.skolemizeExistential(context.owner, tree), mode, pt, original) case et @ ExistentialType(_, _) if ((mode & (EXPRmode | LHSmode)) == EXPRmode) => adapt(tree setType et.skolemizeExistential(context.owner, tree), mode, pt, original) case PolyType(tparams, restpe) if inNoModes(mode, TAPPmode | PATTERNmode | HKmode) => // (3) @@ -1105,7 +1105,7 @@ trait Typers extends Modes with Adaptations with Tags { if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original) else { if (inExprModeButNot(mode, FUNmode)) { - pt.normalize match { + pt.dealias match { case TypeRef(_, sym, _) => // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially // infinite expansion if pt is constant type () @@ -1251,7 +1251,7 @@ trait Typers extends Modes with Adaptations with Tags { def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean = true, saveErrors: Boolean = true): Tree = { if (isAdaptableWithView(qual)) { - qual.tpe.widen.normalize match { + qual.tpe.dealiasWiden match { case et: ExistentialType => qual setType et.skolemizeExistential(context.owner, qual) // open the existential case _ => @@ -1766,7 +1766,7 @@ trait Typers extends Modes with Adaptations with Tags { _.typedTemplate(cdef.impl, parentTypes(cdef.impl)) } val impl2 = finishMethodSynthesis(impl1, clazz, context) - if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.normalize.typeSymbol == AnyClass) + if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass) checkEphemeral(clazz, impl2.body) if ((clazz != ClassfileAnnotationClass) && (clazz isNonBottomSubClass ClassfileAnnotationClass)) @@ -3675,7 +3675,7 @@ trait Typers extends Modes with Adaptations with Tags { val normalizeLocals = new TypeMap { def apply(tp: Type): Type = tp match { case TypeRef(pre, sym, args) => - if (sym.isAliasType && containsLocal(tp)) apply(tp.normalize) + if (sym.isAliasType && containsLocal(tp)) apply(tp.dealias) else { if (pre.isVolatile) InferTypeWithVolatileTypeSelectionError(tree, pre) diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 282d7e18ac..7a63699259 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -563,6 +563,26 @@ trait Types extends api.Types { self: SymbolTable => /** Expands type aliases. */ def dealias = this + /** Repeatedly apply widen and dealias until they have no effect. + * This compensates for the fact that type aliases can hide beneath + * singleton types and singleton types can hide inside type aliases. + */ + def dealiasWiden: Type = ( + if (this ne widen) widen.dealiasWiden + else if (this ne dealias) dealias.dealiasWiden + else this + ) + + /** All the types encountered in the course of dealiasing/widening, + * including each intermediate beta reduction step (whereas calling + * dealias applies as many as possible.) + */ + def dealiasWidenChain: List[Type] = this :: ( + if (this ne widen) widen.dealiasWidenChain + else if (this ne betaReduce) betaReduce.dealiasWidenChain + else Nil + ) + def etaExpand: Type = this /** Performs a single step of beta-reduction on types. @@ -3236,7 +3256,7 @@ trait Types extends api.Types { self: SymbolTable => if (constr.instValid) constr.inst // get here when checking higher-order subtyping of the typevar by itself // TODO: check whether this ever happens? - else if (isHigherKinded) typeFun(params, applyArgs(params map (_.typeConstructor))) + else if (isHigherKinded) logResult("Normalizing HK $this")(typeFun(params, applyArgs(params map (_.typeConstructor)))) else super.normalize ) override def typeSymbol = origin.typeSymbol @@ -3663,7 +3683,7 @@ trait Types extends api.Types { self: SymbolTable => def existentialAbstraction(tparams: List[Symbol], tpe0: Type): Type = if (tparams.isEmpty) tpe0 else { - val tpe = deAlias(tpe0) + val tpe = normalizeAliases(tpe0) val tpe1 = new ExistentialExtrapolation(tparams) extrapolate tpe var tparams0 = tparams var tparams1 = tparams0 filter tpe1.contains @@ -3677,13 +3697,16 @@ trait Types extends api.Types { self: SymbolTable => newExistentialType(tparams1, tpe1) } - /** Remove any occurrences of type aliases from this type */ - object deAlias extends TypeMap { - def apply(tp: Type): Type = mapOver { - tp match { - case TypeRef(pre, sym, args) if sym.isAliasType => tp.normalize - case _ => tp - } + /** Normalize any type aliases within this type (@see Type#normalize). + * Note that this depends very much on the call to "normalize", not "dealias", + * so it is no longer carries the too-stealthy name "deAlias". + */ + object normalizeAliases extends TypeMap { + def apply(tp: Type): Type = tp match { + case TypeRef(_, sym, _) if sym.isAliasType => + def msg = if (tp.isHigherKinded) s"Normalizing type alias function $tp" else s"Dealiasing type alias $tp" + mapOver(logResult(msg)(tp.normalize)) + case _ => mapOver(tp) } } diff --git a/test/files/run/existentials3-old.check b/test/files/run/existentials3-old.check index 72abfac637..36a458dacc 100644 --- a/test/files/run/existentials3-old.check +++ b/test/files/run/existentials3-old.check @@ -5,7 +5,7 @@ Object with Test$ToS Object with Test$ToS scala.Function0[Object with Test$ToS] scala.Function0[Object with Test$ToS] -_ <: Object with _ <: Object with Test$ToS +_ <: Object with _ <: Object with Object with Test$ToS _ <: Object with _ <: Object with _ <: Object with Test$ToS scala.collection.immutable.List[Object with scala.collection.Seq[Int]] scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int]] @@ -16,7 +16,7 @@ Object with Test$ToS Object with Test$ToS scala.Function0[Object with Test$ToS] scala.Function0[Object with Test$ToS] -_ <: Object with _ <: Object with Test$ToS +_ <: Object with _ <: Object with Object with Test$ToS _ <: Object with _ <: Object with _ <: Object with Test$ToS scala.collection.immutable.List[Object with scala.collection.Seq[Int]] scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int]] |