summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-01-11 23:07:12 -0800
committerPaul Phillips <paulp@improving.org>2013-01-11 23:07:12 -0800
commit9ea0a208346e86031a58fa9c28daf6103778a02f (patch)
treeccfa174994cfec5904e35e4fe7d46b2b605dd7ed /src
parent275839d8c3767dae8dd07d1bf8b7e9e87cb369ea (diff)
parente5da30b843fe8bfe1638e3e08cdeaa4b6ae2f2d1 (diff)
downloadscala-9ea0a208346e86031a58fa9c28daf6103778a02f.tar.gz
scala-9ea0a208346e86031a58fa9c28daf6103778a02f.tar.bz2
scala-9ea0a208346e86031a58fa9c28daf6103778a02f.zip
Merge pull request #1869 from retronym/backport/1826
Backport of SI-6846.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala10
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala113
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala55
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala60
6 files changed, 92 insertions, 160 deletions
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index 13880bb8af..d14b5c79e0 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -37,8 +37,8 @@ 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(sym: Symbol): String = relativize(sym.info)
+ def relativize(tp: Type): String = relativize(tp.dealiasWiden.toString)
+ def relativize(sym: Symbol): String = relativize(sym.info)
def braceList(tparams: List[String]) = if (tparams.isEmpty) "" else (tparams map relativize).mkString("[", ", ", "]")
def parenList(params: List[Any]) = params.mkString("(", ", ", ")")
@@ -56,8 +56,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
}
@@ -65,7 +65,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 2b97f81024..b46d28dec3 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -550,7 +550,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 70a736c91f..10003723fd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -443,8 +443,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
}
@@ -488,7 +488,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
@@ -532,18 +532,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
}
@@ -1018,7 +1015,7 @@ trait Implicits {
args foreach (getParts(_))
}
} else if (sym.isAliasType) {
- getParts(tp.normalize)
+ getParts(tp.dealias)
} else if (sym.isAbstractType) {
getParts(tp.bounds.hi)
}
@@ -1049,88 +1046,6 @@ trait Implicits {
infoMap
}
- /** The parts of a type is the smallest set of types that contains
- * - the type itself
- * - the parts of its immediate components (prefix and argument)
- * - the parts of its base types
- * - for alias types and abstract types, we take instead the parts
- * - of their upper bounds.
- * @return For those parts that refer to classes with companion objects that
- * can be accessed with unambiguous stable prefixes, the implicits infos
- * which are members of these companion objects.
-
- private def companionImplicits(tp: Type): Infoss = {
- val partMap = new LinkedHashMap[Symbol, Type]
- val seen = mutable.HashSet[Type]() // cycle detection
-
- /** Enter all parts of `tp` into `parts` set.
- * This method is performance critical: about 2-4% of all type checking is spent here
- */
- def getParts(tp: Type) {
- if (seen(tp))
- return
- seen += tp
- tp match {
- case TypeRef(pre, sym, args) =>
- if (sym.isClass) {
- if (!((sym.name == tpnme.REFINE_CLASS_NAME) ||
- (sym.name startsWith tpnme.ANON_CLASS_NAME) ||
- (sym.name == tpnme.ROOT)))
- partMap get sym match {
- case Some(pre1) =>
- if (!(pre =:= pre1)) partMap(sym) = NoType // ambiguous prefix - ignore implicit members
- case None =>
- if (pre.isStable) partMap(sym) = pre
- val bts = tp.baseTypeSeq
- var i = 1
- while (i < bts.length) {
- getParts(bts(i))
- i += 1
- }
- getParts(pre)
- args foreach getParts
- }
- } else if (sym.isAliasType) {
- getParts(tp.normalize)
- } else if (sym.isAbstractType) {
- getParts(tp.bounds.hi)
- }
- case ThisType(_) =>
- getParts(tp.widen)
- case _: SingletonType =>
- getParts(tp.widen)
- case RefinedType(ps, _) =>
- for (p <- ps) getParts(p)
- case AnnotatedType(_, t, _) =>
- getParts(t)
- case ExistentialType(_, t) =>
- getParts(t)
- case PolyType(_, t) =>
- getParts(t)
- case _ =>
- }
- }
-
- getParts(tp)
-
- val buf = new ListBuffer[Infos]
- for ((clazz, pre) <- partMap) {
- if (pre != NoType) {
- val companion = clazz.companionModule
- companion.moduleClass match {
- case mc: ModuleClassSymbol =>
- buf += (mc.implicitMembers map (im =>
- new ImplicitInfo(im.name, singleType(pre, companion), im)))
- case _ =>
- }
- }
- }
- //println("companion implicits of "+tp+" = "+buf.toList) // DEBUG
- buf.toList
- }
-
-*/
-
/** The implicits made available by type `pt`.
* These are all implicits found in companion objects of classes C
* such that some part of `tp` has C as one of its superclasses.
@@ -1258,7 +1173,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 7ae8923e43..0f52687c75 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -44,7 +44,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
}
@@ -1060,15 +1060,17 @@ trait Infer extends Checkable {
*/
def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): List[Symbol] = {
val treeTp = if(treeTp0 eq null) tree.tpe else treeTp0 // can't refer to tree in default for treeTp0
+ val (targs, tvars) = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible)
printInference(
ptBlock("inferExprInstance",
"tree" -> tree,
"tree.tpe"-> tree.tpe,
"tparams" -> tparams,
- "pt" -> pt
+ "pt" -> pt,
+ "targs" -> targs,
+ "tvars" -> tvars
)
)
- val (targs, tvars) = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible)
if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226
substExpr(tree, tparams, targs, pt)
@@ -1422,9 +1424,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 1dce2c633d..386eec207a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -224,7 +224,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
@@ -439,7 +439,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)
@@ -1075,9 +1075,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)
@@ -1147,7 +1147,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 ()
@@ -1302,7 +1302,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 _ =>
@@ -1840,7 +1840,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))
@@ -3868,7 +3868,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)
@@ -4396,7 +4396,13 @@ trait Typers extends Modes with Adaptations with Tags {
def typedNew(tree: New) = {
val tpt = tree.tpt
val tpt1 = {
- val tpt0 = typedTypeConstructor(tpt)
+ // This way typedNew always returns a dealiased type. This used to happen by accident
+ // for instantiations without type arguments due to ad hoc code in typedTypeConstructor,
+ // and annotations depended on it (to the extent that they worked, which they did
+ // not when given a parameterized type alias which dealiased to an annotation.)
+ // typedTypeConstructor dealiases nothing now, but it makes sense for a "new" to always be
+ // given a dealiased type.
+ val tpt0 = typedTypeConstructor(tpt) modifyType (_.dealias)
if (checkStablePrefixClassType(tpt0))
if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) {
context.undetparams = cloneSymbols(tpt0.symbol.typeParams)
@@ -5736,29 +5742,18 @@ trait Typers extends Modes with Adaptations with Tags {
def typedTypeConstructor(tree: Tree, mode: Int): Tree = {
val result = typed(tree, forTypeMode(mode) | FUNmode, WildcardType)
- val restpe = result.tpe.normalize // normalize to get rid of type aliases for the following check (#1241)
- if (!phase.erasedTypes && restpe.isInstanceOf[TypeRef] && !restpe.prefix.isStable && !context.unit.isJava) {
- // The isJava exception if OK only because the only type constructors scalac gets
- // to see are those in the signatures. These do not need a unique object as a prefix.
- // The situation is different for new's and super's, but scalac does not look deep
- // enough to see those. See #3938
- ConstructorPrefixError(tree, restpe)
- } else {
- //@M fix for #2208
- // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
- if (result.tpe.typeArgs.isEmpty) {
- // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
- // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
- // designed to deal with the cycles in the scala package (ScalaObject extends
- // AnyRef, but the AnyRef type alias is entered after the scala package is
- // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
- // yet defined )
- // !!! TODO - revisit now that ScalaObject is gone.
- result setType(restpe)
- } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
+ // get rid of type aliases for the following check (#1241)
+ result.tpe.dealias match {
+ case restpe @ TypeRef(pre, _, _) if !phase.erasedTypes && !pre.isStable && !context.unit.isJava =>
+ // The isJava exception if OK only because the only type constructors scalac gets
+ // to see are those in the signatures. These do not need a unique object as a prefix.
+ // The situation is different for new's and super's, but scalac does not look deep
+ // enough to see those. See #3938
+ ConstructorPrefixError(tree, restpe)
+ case _ =>
+ // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
// during uncurry (after refchecks), all types are normalized
result
- }
}
}
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index bfd18f6a43..c2637e6967 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -593,6 +593,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.
@@ -3173,23 +3193,20 @@ trait Types extends api.Types { self: SymbolTable =>
* Checks subtyping of higher-order type vars, and uses variances as defined in the
* type parameter we're trying to infer (the result will be sanity-checked later).
*/
- def unifyFull(tpe: Type) = {
- // The alias/widen variations are often no-ops.
- val tpes = (
- if (isLowerBound) List(tpe, tpe.widen, tpe.dealias, tpe.widen.dealias).distinct
- else List(tpe)
- )
- tpes exists { tp =>
- val lhs = if (isLowerBound) tp.typeArgs else typeArgs
- val rhs = if (isLowerBound) typeArgs else tp.typeArgs
-
- sameLength(lhs, rhs) && {
+ def unifyFull(tpe: Type): Boolean = {
+ def unifySpecific(tp: Type) = {
+ sameLength(typeArgs, tp.typeArgs) && {
+ val lhs = if (isLowerBound) tp.typeArgs else typeArgs
+ val rhs = if (isLowerBound) typeArgs else tp.typeArgs
// this is a higher-kinded type var with same arity as tp.
// side effect: adds the type constructor itself as a bound
addBound(tp.typeConstructor)
isSubArgs(lhs, rhs, params, AnyDepth)
}
}
+ // The type with which we can successfully unify can be hidden
+ // behind singleton types and type aliases.
+ tpe.dealiasWidenChain exists unifySpecific
}
// There's a <: test taking place right now, where tp is a concrete type and this is a typevar
@@ -3282,7 +3299,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
@@ -3754,7 +3771,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
@@ -3768,13 +3785,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)
}
}