Permalink
Browse files

Changes many calls to normalize to dealiasWiden.

Calling normalize is very aggressive and is usually the wrong
thing. It is one of the leading contributors to non-determinism
in compiler outcomes (often of the form "I gave a debugging or
logging compiler option and it started/stopped working") and
should be used only in very specific circumstances.

Almost without exception, dealiasWiden is what you want; not
widen, not normalize. If possible I will remove normalize from
Type entirely, making it private to those areas of the compiler
which actually require it.
  • Loading branch information...
1 parent 0388a7c commit 039b1cb1a5b8738bb3731035838d2fcaeb317d07 @paulp paulp committed Jan 29, 2013
View
2 src/compiler/scala/reflect/reify/package.scala
@@ -56,7 +56,7 @@ package object reify {
if (concrete) throw new ReificationException(enclosingMacroPosition, "tpe %s is an unresolved spliceable type".format(tpe))
}
- tpe.normalize match {
+ tpe.dealiasWiden match {
case TypeRef(_, ArrayClass, componentTpe :: Nil) =>
val componentErasure = reifyRuntimeClass(global)(typer0, componentTpe, concrete)
gen.mkMethodCall(arrayClassMethod, List(componentErasure))
View
4 src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -368,10 +368,10 @@ trait TypeKinds { self: ICodes =>
/** Return the TypeKind of the given type
*
- * Call to .normalize fixes #3003 (follow type aliases). Otherwise,
+ * Call to dealiasWiden fixes #3003 (follow type aliases). Otherwise,
* arrayOrClassType below would return ObjectReference.
*/
- def toTypeKind(t: Type): TypeKind = t.normalize match {
+ def toTypeKind(t: Type): TypeKind = t.dealiasWiden match {
case ThisType(ArrayClass) => ObjectReference
case ThisType(sym) => REFERENCE(sym)
case SingleType(_, sym) => primitiveOrRefType(sym)
View
2 src/compiler/scala/tools/nsc/dependencies/Changes.scala
@@ -90,11 +90,11 @@ abstract class Changes {
} else
!sym1.isTypeParameter || !changedTypeParams.contains(sym1.fullName)
+ // @M! normalize reduces higher-kinded case to PolyType's
testSymbols && sameType(pre1, pre2) &&
(sym1.variance == sym2.variance) &&
((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) ||
sameTypes(args1, args2))
- // @M! normalize reduces higher-kinded case to PolyType's
case (RefinedType(parents1, ref1), RefinedType(parents2, ref2)) =>
def isSubScope(s1: Scope, s2: Scope): Boolean = s2.toList.forall {
View
2 src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -75,7 +75,7 @@ trait CompletionOutput {
}
def methodString() =
- method.keyString + " " + method.nameString + (method.info.normalize match {
+ method.keyString + " " + method.nameString + (method.info.dealiasWiden match {
case NullaryMethodType(resType) => ": " + typeToString(resType)
case PolyType(tparams, resType) => tparamsString(tparams) + typeToString(resType)
case mt @ MethodType(_, _) => methodTypeToString(mt)
View
10 src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -101,7 +101,7 @@ abstract class Erasure extends AddInterfaces
* unboxing some primitive types and further simplifications as they are done in jsig.
*/
val prepareSigMap = new TypeMap {
- def squashBoxed(tp: Type): Type = tp.normalize match {
+ def squashBoxed(tp: Type): Type = tp.dealiasWiden match {
case t @ RefinedType(parents, decls) =>
val parents1 = parents mapConserve squashBoxed
if (parents1 eq parents) tp
@@ -114,7 +114,7 @@ abstract class Erasure extends AddInterfaces
if (boxedClass contains t.typeSymbol) ObjectClass.tpe
else tp
}
- def apply(tp: Type): Type = tp.normalize match {
+ def apply(tp: Type): Type = tp.dealiasWiden match {
case tp1 @ TypeBounds(lo, hi) =>
val lo1 = squashBoxed(apply(lo))
val hi1 = squashBoxed(apply(hi))
@@ -145,7 +145,7 @@ abstract class Erasure extends AddInterfaces
}
case tp1 @ MethodType(params, restpe) =>
val params1 = mapOver(params)
- val restpe1 = if (restpe.normalize.typeSymbol == UnitClass) UnitClass.tpe else apply(restpe)
+ val restpe1 = if (restpe.typeSymbol == UnitClass) UnitClass.tpe else apply(restpe)
if ((params1 eq params) && (restpe1 eq restpe)) tp1
else MethodType(params1, restpe1)
case tp1 @ RefinedType(parents, decls) =>
@@ -163,8 +163,8 @@ abstract class Erasure extends AddInterfaces
}
}
- private def hiBounds(bounds: TypeBounds): List[Type] = bounds.hi.normalize match {
- case RefinedType(parents, _) => parents map (_.normalize)
+ private def hiBounds(bounds: TypeBounds): List[Type] = bounds.hi.dealiasWiden match {
+ case RefinedType(parents, _) => parents map (_.dealiasWiden)
case tp => tp :: Nil
}
View
2 src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -424,7 +424,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
def specializedTypeVars(tpe: Type): immutable.Set[Symbol] = tpe match {
case TypeRef(pre, sym, args) =>
if (sym.isAliasType)
- specializedTypeVars(tpe.normalize)
+ specializedTypeVars(tpe.dealiasWiden)
else if (sym.isTypeParameter && sym.isSpecialized || (sym.isTypeSkolem && sym.deSkolemize.isSpecialized))
Set(sym)
else if (sym == ArrayClass)
View
2 src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -153,7 +153,7 @@ trait ContextErrors {
// members present, then display along with the expected members. This is done here because
// this is the last point where we still have access to the original tree, rather than just
// the found/req types.
- val foundType: Type = req.normalize match {
+ val foundType: Type = req.dealiasWiden match {
case RefinedType(parents, decls) if !decls.isEmpty && found.typeSymbol.isAnonOrRefinementClass =>
val retyped = typed (tree.duplicate.clearType())
val foundDecls = retyped.tpe.decls filter (sym => !sym.isConstructor && !sym.isSynthetic)
View
6 src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -347,7 +347,7 @@ trait Implicits {
* if one or both are intersection types with a pair of overlapping parent types.
*/
private def dominates(dtor: Type, dted: Type): Boolean = {
- def core(tp: Type): Type = tp.normalize match {
+ def core(tp: Type): Type = tp.dealiasWiden match {
case RefinedType(parents, defs) => intersectionType(parents map core, tp.typeSymbol.owner)
case AnnotatedType(annots, tp, selfsym) => core(tp)
case ExistentialType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi)))
@@ -362,11 +362,11 @@ trait Implicits {
deriveTypeWithWildcards(syms.distinct)(tp)
}
def sum(xs: List[Int]) = (0 /: xs)(_ + _)
- def complexity(tp: Type): Int = tp.normalize match {
+ def complexity(tp: Type): Int = tp.dealiasWiden match {
case NoPrefix =>
0
case SingleType(pre, sym) =>
- if (sym.isPackage) 0 else complexity(tp.normalize.widen)
+ if (sym.isPackage) 0 else complexity(tp.dealiasWiden)
case TypeRef(pre, sym, args) =>
complexity(pre) + sum(args map complexity) + 1
case RefinedType(parents, _) =>
View
2 src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -477,7 +477,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
**/
// must treat Typed and Bind together -- we need to know the patBinder of the Bind pattern to get at the actual type
case MaybeBoundTyped(subPatBinder, pt) =>
- val next = glb(List(patBinder.info.widen, pt)).normalize
+ val next = glb(List(patBinder.info.dealiasWiden, pt)).normalize
// a typed pattern never has any subtrees
noFurtherSubPats(TypeTestTreeMaker(subPatBinder, patBinder, pt, next)(pos))
View
12 src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -68,7 +68,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (sym.hasAccessBoundary) "" + sym.privateWithin.name else ""
)
- def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type): Boolean = (tp1.normalize, tp2.normalize) match {
+ def overridesTypeInPrefix(tp1: Type, tp2: Type, prefix: Type): Boolean = (tp1.dealiasWiden, tp2.dealiasWiden) match {
case (MethodType(List(), rtp1), NullaryMethodType(rtp2)) =>
rtp1 <:< rtp2
case (NullaryMethodType(rtp1), MethodType(List(), rtp2)) =>
@@ -472,12 +472,12 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// check a type alias's RHS corresponds to its declaration
// this overlaps somewhat with validateVariance
if(member.isAliasType) {
- // println("checkKindBounds" + ((List(member), List(memberTp.normalize), self, member.owner)))
- val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.normalize), self, member.owner)
+ // println("checkKindBounds" + ((List(member), List(memberTp.dealiasWiden), self, member.owner)))
+ val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.dealiasWiden), self, member.owner)
if(!kindErrors.isEmpty)
unit.error(member.pos,
- "The kind of the right-hand side "+memberTp.normalize+" of "+member.keyString+" "+
+ "The kind of the right-hand side "+memberTp.dealiasWiden+" of "+member.keyString+" "+
member.varianceString + member.nameString+ " does not conform to its expected kind."+
kindErrors.toList.mkString("\n", ", ", ""))
} else if (member.isAbstractType) {
@@ -496,7 +496,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (member.isStable && !otherTp.isVolatile) {
if (memberTp.isVolatile)
overrideError("has a volatile type; cannot override a member with non-volatile type")
- else memberTp.normalize.resultType match {
+ else memberTp.dealiasWiden.resultType match {
case rt: RefinedType if !(rt =:= otherTp) && !(checkedCombinations contains rt.parents) =>
// might mask some inconsistencies -- check overrides
checkedCombinations += rt.parents
@@ -1298,7 +1298,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// if the unnormalized type is accessible, that's good enough
if (inaccessible.isEmpty) ()
// or if the normalized type is, that's good too
- else if ((tpe ne tpe.normalize) && lessAccessibleSymsInType(tpe.normalize, member).isEmpty) ()
+ else if ((tpe ne tpe.normalize) && lessAccessibleSymsInType(tpe.dealiasWiden, member).isEmpty) ()
// otherwise warn about the inaccessible syms in the unnormalized type
else inaccessible foreach (sym => warnLessAccessible(sym, member))
}
View
2 src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -213,7 +213,7 @@ trait TypeDiagnostics {
// force measures than comparing normalized Strings were producing error messages
// like "and java.util.ArrayList[String] <: java.util.ArrayList[String]" but there
// should be a cleaner way to do this.
- if (found.normalize.toString == tp.normalize.toString) ""
+ if (found.dealiasWiden.toString == tp.dealiasWiden.toString) ""
else " (and %s <: %s)".format(found, tp)
)
val explainDef = {
View
14 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2437,7 +2437,7 @@ trait Typers extends Adaptations with Tags {
// but not in real life (i.e., now that's we've reset the method's type skolems'
// infos back to their pre-GADT-constraint state)
if (isFullyDefined(pt) && !(body1.tpe <:< pt))
- body1 = typedPos(body1.pos)(gen.mkCast(body1, pt.normalize))
+ body1 = typedPos(body1.pos)(gen.mkCast(body1, pt.dealiasWiden))
}
@@ -2507,7 +2507,7 @@ trait Typers extends Adaptations with Tags {
*/
def synthesizePartialFunction(paramName: TermName, paramPos: Position, tree: Tree, mode: Mode, pt: Type): Tree = {
assert(pt.typeSymbol == PartialFunctionClass, s"PartialFunction synthesis for match in $tree requires PartialFunction expected type, but got $pt.")
- val targs = pt.normalize.typeArgs
+ val targs = pt.dealiasWiden.typeArgs
// if targs.head isn't fully defined, we can translate --> error
targs match {
@@ -2665,10 +2665,10 @@ trait Typers extends Adaptations with Tags {
def decompose(pt: Type): (Symbol, List[Type], Type) =
if ((isFunctionType(pt) || (pt.typeSymbol == PartialFunctionClass && numVparams == 1 && fun.body.isInstanceOf[Match])) && // see bug901 for a reason why next conditions are needed
- ( pt.normalize.typeArgs.length - 1 == numVparams
+ ( pt.dealiasWiden.typeArgs.length - 1 == numVparams
|| fun.vparams.exists(_.tpt.isEmpty)
))
- (pt.typeSymbol, pt.normalize.typeArgs.init, pt.normalize.typeArgs.last)
+ (pt.typeSymbol, pt.dealiasWiden.typeArgs.init, pt.dealiasWiden.typeArgs.last)
else
(FunctionClass(numVparams), fun.vparams map (x => NoType), WildcardType)
@@ -3316,7 +3316,7 @@ trait Typers extends Adaptations with Tags {
if (fun1.tpe.isErroneous) duplErrTree
else {
- val resTp = fun1.tpe.finalResultType.normalize
+ val resTp = fun1.tpe.finalResultType.dealiasWiden
val nbSubPats = args.length
val (formals, formalsExpanded) = extractorFormalTypes(fun0.pos, resTp, nbSubPats, fun1.symbol)
@@ -3364,7 +3364,7 @@ trait Typers extends Adaptations with Tags {
def extractorForUncheckedType(pos: Position, pt: Type): Option[Tree] = if (isPastTyper) None else {
// only look at top-level type, can't (reliably) do anything about unchecked type args (in general)
// but at least make a proper type before passing it elsewhere
- val pt1 = pt.dealias match {
+ val pt1 = pt.dealiasWiden match {
case tr @ TypeRef(pre, sym, args) if args.nonEmpty => copyTypeRef(tr, pre, sym, sym.typeParams map (_.tpeHK)) // replace actual type args with dummies
case pt1 => pt1
}
@@ -4209,7 +4209,7 @@ trait Typers extends Adaptations with Tags {
if (newPatternMatching && (pt.typeSymbol == PartialFunctionClass))
synthesizePartialFunction(newTermName(context.unit.fresh.newName("x")), tree.pos, tree, mode, pt)
else {
- val arity = if (isFunctionType(pt)) pt.normalize.typeArgs.length - 1 else 1
+ val arity = if (isFunctionType(pt)) pt.dealiasWiden.typeArgs.length - 1 else 1
val params = for (i <- List.range(0, arity)) yield
atPos(tree.pos.focusStart) {
ValDef(Modifiers(PARAM | SYNTHETIC),
View
2 src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala
@@ -61,7 +61,7 @@ trait CPSUtils {
// annotation checker
protected def annTypes(ann: AnnotationInfo): (Type, Type) = {
- val tp0 :: tp1 :: Nil = ann.atp.normalize.typeArgs
+ val tp0 :: tp1 :: Nil = ann.atp.dealiasWiden.typeArgs
((tp0, tp1))
}
protected def hasMinusMarker(tpe: Type) = tpe hasAnnotation MarkerCPSAdaptMinus
View
10 src/reflect/scala/reflect/internal/Definitions.scala
@@ -626,7 +626,7 @@ trait Definitions extends api.StandardDefinitions {
len <= MaxTupleArity && sym == TupleClass(len)
case _ => false
}
- def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize)
+ def isTupleType(tp: Type) = isTupleTypeDirect(tp.dealiasWiden)
lazy val ProductRootClass: ClassSymbol = requiredClass[scala.Product]
def Product_productArity = getMemberMethod(ProductRootClass, nme.productArity)
@@ -648,16 +648,16 @@ trait Definitions extends api.StandardDefinitions {
case _ => tp
}
- def unapplyUnwrap(tpe:Type) = tpe.finalResultType.normalize match {
- case RefinedType(p :: _, _) => p.normalize
+ def unapplyUnwrap(tpe:Type) = tpe.finalResultType.dealiasWiden match {
+ case RefinedType(p :: _, _) => p.dealiasWiden
case tp => tp
}
def abstractFunctionForFunctionType(tp: Type) =
if (isFunctionType(tp)) abstractFunctionType(tp.typeArgs.init, tp.typeArgs.last)
else NoType
- def isFunctionType(tp: Type): Boolean = tp.normalize match {
+ def isFunctionType(tp: Type): Boolean = tp.dealiasWiden match {
case TypeRef(_, sym, args) if args.nonEmpty =>
val arity = args.length - 1 // -1 is the return type
arity <= MaxFunctionArity && sym == FunctionClass(arity)
@@ -1145,7 +1145,7 @@ trait Definitions extends api.StandardDefinitions {
else if (sym.isTopLevel) sym.javaClassName
else flatNameString(sym.owner, separator) + nme.NAME_JOIN_STRING + sym.simpleName
def signature1(etp: Type): String = {
- if (etp.typeSymbol == ArrayClass) "[" + signature1(erasure(etp.normalize.typeArgs.head))
+ if (etp.typeSymbol == ArrayClass) "[" + signature1(erasure(etp.dealiasWiden.typeArgs.head))
else if (isPrimitiveValueClass(etp.typeSymbol)) abbrvTag(etp.typeSymbol).toString()
else "L" + flatNameString(etp.typeSymbol, '/') + ";"
}
View
2 src/reflect/scala/reflect/internal/Symbols.scala
@@ -844,7 +844,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** Is this class or type defined as a structural refinement type?
*/
final def isStructuralRefinement: Boolean =
- (isClass || isType || isModule) && info.normalize/*.underlying*/.isStructuralRefinement
+ (isClass || isType || isModule) && info.dealiasWiden/*.underlying*/.isStructuralRefinement
/** Is this a term symbol only defined in a refinement (so that it needs
* to be accessed by reflection)?
View
2 src/reflect/scala/reflect/internal/TreeGen.scala
@@ -212,7 +212,7 @@ abstract class TreeGen extends macros.TreeBuilder {
mkTypeApply(mkAttributedSelect(target, method), targs map TypeTree)
private def mkSingleTypeApply(value: Tree, tpe: Type, what: Symbol, wrapInApply: Boolean) = {
- val tapp = mkAttributedTypeApply(value, what, tpe.normalize :: Nil)
+ val tapp = mkAttributedTypeApply(value, what, tpe.dealias :: Nil)
if (wrapInApply) Apply(tapp, Nil) else tapp
}
private def typeTestSymbol(any: Boolean) = if (any) Any_isInstanceOf else Object_isInstanceOf
View
2 src/reflect/scala/reflect/internal/Types.scala
@@ -2456,7 +2456,7 @@ trait Types extends api.Types { self: SymbolTable =>
case RepeatedParamClass => args.head + "*"
case ByNameParamClass => "=> " + args.head
case _ =>
- def targs = normalize.typeArgs
+ def targs = dealiasWiden.typeArgs
if (isFunctionType(this)) {
// Aesthetics: printing Function1 as T => R rather than (T) => R
View
6 src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -16,7 +16,7 @@ trait Erasure {
/** Is `tp` an unbounded generic type (i.e. which could be instantiated
* with primitive as well as class types)?.
*/
- private def genericCore(tp: Type): Type = tp.normalize match {
+ private def genericCore(tp: Type): Type = tp.dealiasWiden match {
/* A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is
* erased to Object. However, there is only symbol for the Array class. So to make the distinction between
* a Java and a Scala array, we check if the owner of T comes from a Java class.
@@ -36,7 +36,7 @@ trait Erasure {
* then Some((N, T)) where N is the number of Array constructors enclosing `T`,
* otherwise None. Existentials on any level are ignored.
*/
- def unapply(tp: Type): Option[(Int, Type)] = tp.normalize match {
+ def unapply(tp: Type): Option[(Int, Type)] = tp.dealiasWiden match {
case TypeRef(_, ArrayClass, List(arg)) =>
genericCore(arg) match {
case NoType =>
@@ -101,7 +101,7 @@ trait Erasure {
def valueClassIsParametric(clazz: Symbol): Boolean = {
assert(!phase.erasedTypes)
clazz.typeParams contains
- clazz.derivedValueClassUnbox.tpe.resultType.normalize.typeSymbol
+ clazz.derivedValueClassUnbox.tpe.resultType.typeSymbol
}
abstract class ErasureMap extends TypeMap {
View
10 src/reflect/scala/reflect/internal/transform/UnCurry.scala
@@ -10,6 +10,14 @@ trait UnCurry {
import global._
import definitions._
+ /** Note: changing tp.normalize to tp.dealias in this method leads to a single
+ * test failure: run/t5688.scala, where instead of the expected output
+ * Vector(ta, tb, tab)
+ * we instead get
+ * Vector(tab, tb, tab)
+ * I think that difference is not the product of sentience but of randomness.
+ * Let us figure out why it is and then change this method.
+ */
private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp
val uncurry: TypeMap = new TypeMap {
@@ -60,4 +68,4 @@ trait UnCurry {
*/
def transformInfo(sym: Symbol, tp: Type): Type =
if (sym.isType) uncurryType(tp) else uncurry(tp)
-}
+}
View
12 test/files/neg/t2641.check
@@ -1,15 +1,7 @@
t2641.scala:18: error: wrong number of type arguments for ManagedSeq, should be 2
with TraversableViewLike[A, ManagedSeqStrict[A], ManagedSeq[A]]
^
-t2641.scala:16: error: illegal inheritance;
- self-type ManagedSeq does not conform to ManagedSeqStrict[A]'s selftype ManagedSeqStrict[A]
- extends ManagedSeqStrict[A]
- ^
-t2641.scala:17: error: illegal inheritance;
- self-type ManagedSeq does not conform to scala.collection.TraversableView[A,ManagedSeqStrict[A]]'s selftype scala.collection.TraversableView[A,ManagedSeqStrict[A]]
- with TraversableView[A, ManagedSeqStrict[A]]
- ^
-t2641.scala:27: error: value managedIterator is not a member of ManagedSeq
+t2641.scala:27: error: value managedIterator is not a member of ManagedSeq[A,Coll]
override def managedIterator = self.managedIterator slice (from, until)
^
-four errors found
+two errors found

0 comments on commit 039b1cb

Please sign in to comment.