summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-12-21 15:11:29 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2012-12-28 15:16:49 -0800
commit3bf51189f979eb0dd41744ca844fd12dfdaa0dee (patch)
treea5317cbc2cafad735cd2d3fa27c28d99785361e7
parent422f461578ae0547181afe6d2c0c52ea1071d37b (diff)
downloadscala-3bf51189f979eb0dd41744ca844fd12dfdaa0dee.tar.gz
scala-3bf51189f979eb0dd41744ca844fd12dfdaa0dee.tar.bz2
scala-3bf51189f979eb0dd41744ca844fd12dfdaa0dee.zip
Cleaning up type alias usage.
I determined that many if not most of the calls to .normalize have no intent beyond dealiasing the type. In light of this I went call site to call site knocking on doors and asking why exactly they were calling any of .normalize .widen.normalize .normalize.widen and if I didn't like their answers they found themselves introduced to 'dropAliasesAndSingleTypes', the recursive widener and dealiaser which I concluded is necessary after all. Discovered that the object called 'deAlias' actually depends upon calling 'normalize', not 'dealias'. Decided this was sufficient cause to rename it to 'normalizeAliases'. Created dealiasWiden and dealiasWidenChain. Dropped dropAliasesAndSingleTypes in favor of methods on Type alongside dealias and widen (Type#dealiasWiden). These should reduce the number of "hey, the type alias doesn't work" bugs.
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala8
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala18
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala41
-rw-r--r--test/files/run/existentials3-old.check4
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]]