summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2009-08-13 08:37:24 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2009-08-13 08:37:24 +0000
commit2416d5724eb7fba3ed5b80092194a27e333a23f3 (patch)
tree6432d8e90ca5c1ed1b6c65798ee06679f70b6735 /src
parent1ceff6729ae30c61ec43e615daf9ef96ea59aae7 (diff)
downloadscala-2416d5724eb7fba3ed5b80092194a27e333a23f3.tar.gz
scala-2416d5724eb7fba3ed5b80092194a27e333a23f3.tar.bz2
scala-2416d5724eb7fba3ed5b80092194a27e333a23f3.zip
fixed #2246 type checker looping on pos/contrib701
be more careful in isSubType for abstract types: type *constructors* must be different, not the whole type, which includes type arguments typeConstructor needed to instantiate the resulting type constructor with fresh type arguments (derived from type params), otherwise we end up in the higher-kinded case, and isDifferentTypeConstructor might try to compare polytypes with type params that have different (higher-order) arities --> this may still arise on other cases, though -- should fix this while working on #2210
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala72
1 files changed, 42 insertions, 30 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index c2f915e570..6f945b23e5 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -138,6 +138,7 @@ trait Types {
// Important to keep this up-to-date when new operations are added!
override def isTrivial = underlying.isTrivial
override def isHigherKinded: Boolean = underlying.isHigherKinded
+ override def typeConstructor(dummyArgs: Boolean): Type = underlying.typeConstructor(dummyArgs)
override def isNotNull = underlying.isNotNull
override def isError = underlying.isError
override def isErroneous = underlying.isErroneous
@@ -295,6 +296,9 @@ trait Types {
case _ => List()
}
+ /** This type, without type arguments (if !dummyArgs), or with fresh dummy type arguments (if dummyArgs) @M */
+ def typeConstructor(dummyArgs: Boolean): Type = this
+
/** For a typeref, its arguments. The empty list for all other types */
def typeArgs: List[Type] = List()
@@ -1153,12 +1157,15 @@ trait Types {
override def isHigherKinded =
!parents.isEmpty && (parents forall (_.isHigherKinded)) // @MO to AM: please check this class!
+ //@M may result in an invalid type (references to higher-order args become dangling )
+ override def typeConstructor(dummyArgs: Boolean) =
+ copyRefinedType(this, parents map (_.typeConstructor(dummyArgs)), decls)
+
override def typeParams =
if (isHigherKinded) parents.head.typeParams
else super.typeParams
- private def higherKindedArgs =
- typeParams map (_.typeConstructor)
+ private def dummyArgs = typeParams map (_.typeConstructor)
/* MO to AM: This is probably not correct
* If they are several higher-kinded parents with different bounds we need
@@ -1171,7 +1178,7 @@ trait Types {
refinementOfClass(
typeSymbol,
parents map {
- case TypeRef(pre, sym, List()) => TypeRef(pre, sym, higherKindedArgs)
+ case TypeRef(pre, sym, List()) => TypeRef(pre, sym, dummyArgs)
case p => p
},
decls))
@@ -1407,17 +1414,15 @@ trait Types {
// @M: propagate actual type params (args) to `tp', by replacing formal type parameters with actual ones
def transform(tp: Type): Type = {
- val args = argsMaybeDummy
+ val args = typeArgsOrDummies
if (args.length == sym.typeParams.length)
- tp.asSeenFrom(pre, sym.owner).instantiateTypeParams(sym.typeParams, argsMaybeDummy)
+ tp.asSeenFrom(pre, sym.owner).instantiateTypeParams(sym.typeParams, args)
else { assert(sym.typeParams.isEmpty || (args exists (_.isError)), tp); tp }
// @M TODO maybe we shouldn't instantiate type params if isHigherKinded -- probably needed for partial type application though
}
//@M! use appliedType on the polytype that represents the bounds (or if aliastype, the rhs)
- def transformInfo(tp: Type): Type =
- appliedType(tp.asSeenFrom(pre, sym.owner), argsMaybeDummy)
- // TODO: argsMaybeDummy --> ok? or don't instantiate type params if isHigherKinded
+ def transformInfo(tp: Type): Type = appliedType(tp.asSeenFrom(pre, sym.owner), typeArgsOrDummies)
def thisInfo =
if (sym.isAliasType) normalize
@@ -1473,10 +1478,20 @@ A type's typeSymbol should never be inspected directly.
else pre
override def typeArgs: List[Type] = args
+ private def typeArgsOrDummies = if (!isHigherKinded) args else dummyArgs
+
+ // @MAT was typeSymbol.unsafeTypeParams, but typeSymbol normalizes now
+ private def typeParamsDirect = sym.unsafeTypeParams
- override def typeParams: List[Symbol] =
- if (args.isEmpty) sym.unsafeTypeParams else List()
- // @MAT was typeSymbol.unsafeTypeParams, but typeSymbol normalizes now
+ // placeholders derived from type params
+ private def dummyArgs = typeParamsDirect map (_.typeConstructor) //@M must be .typeConstructor
+ override def typeConstructor(dummyArgs: Boolean) = rawTypeRef(pre, sym, if(dummyArgs) this.dummyArgs else List())
+
+ // (!result.isEmpty) IFF isHigherKinded
+ override def typeParams: List[Symbol] = if (args.isEmpty) typeParamsDirect else List()
+
+ //@M equivalent to (!typeParams.isEmpty && args.isEmpty) because args.isEmpty is checked in typeParams
+ override def isHigherKinded = !typeParams.isEmpty
override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type =
if (isHigherKinded) {
@@ -1485,15 +1500,11 @@ A type's typeSymbol should never be inspected directly.
if (substTps.length == typeParams.length)
typeRef(pre, sym, actuals)
else // partial application (needed in infer when bunching type arguments from classes and methods together)
- typeRef(pre, sym, higherKindedArgs).subst(formals, actuals)
+ typeRef(pre, sym, dummyArgs).subst(formals, actuals)
}
else
super.instantiateTypeParams(formals, actuals)
- override def isHigherKinded = !typeParams.isEmpty //@M args.isEmpty is checked in typeParams
-
- private def higherKindedArgs = typeParams map (_.typeConstructor) //@M must be .typeConstructor
- private def argsMaybeDummy = if (isHigherKinded) higherKindedArgs else args
private var normalized: Type = null
@@ -1519,7 +1530,7 @@ A type's typeSymbol should never be inspected directly.
} else if (isHigherKinded) {
// @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function*
// @M: initialize needed (see test/files/pos/ticket0137.scala)
- PolyType(typeParams, typeRef(pre, sym.initialize, higherKindedArgs))
+ PolyType(typeParams, typeRef(pre, sym.initialize, dummyArgs))
} else if (sym.isRefinementClass) {
sym.info.normalize // @MO to AM: OK?
} else {
@@ -2913,8 +2924,9 @@ A type's typeSymbol should never be inspected directly.
else subst(sym, from.tail, to.tail)
tp match {
case TypeRef(pre, sym, args) if !(pre eq NoPrefix) =>
- mapOver(typeRef(pre, subst(sym, from, to), args))
- //@M TODO subst args? List.mapConserve(args)(this)
+ val newSym = subst(sym, from, to)
+ // assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams))
+ mapOver(typeRef(pre, newSym, args)) // mapOver takes care of subst'ing in args
case SingleType(pre, sym) if !(pre eq NoPrefix) =>
mapOver(singleType(pre, subst(sym, from, to)))
case _ =>
@@ -3482,10 +3494,10 @@ A type's typeSymbol should never be inspected directly.
if (subsametypeRecursions == 0) undoLog = List()
}
- def isDifferentType(tp1: Type, tp2: Type): Boolean = try {
+ def isDifferentTypeConstructor(tp1: Type, tp2: Type): Boolean = try {
subsametypeRecursions += 1
val lastUndoLog = undoLog
- val result = isSameType0(tp1, tp2)
+ val result = isSameType0(tp1.typeConstructor(true), tp2.typeConstructor(true))
undoTo(lastUndoLog)
!result
} finally {
@@ -3567,14 +3579,15 @@ A type's typeSymbol should never be inspected directly.
res1 =:= res2 &&
tp1.isInstanceOf[ImplicitMethodType] == tp2.isInstanceOf[ImplicitMethodType])
case (PolyType(tparams1, res1), PolyType(tparams2, res2)) =>
+// assert((tparams1 map (_.typeParams.length)) == (tparams2 map (_.typeParams.length)))
(tparams1.length == tparams2.length &&
List.forall2(tparams1, tparams2)
- ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) &&
+ ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210
res1 =:= res2.substSym(tparams2, tparams1))
case (ExistentialType(tparams1, res1), ExistentialType(tparams2, res2)) =>
(tparams1.length == tparams2.length &&
List.forall2(tparams1, tparams2)
- ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) &&
+ ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && //@M looks like it might suffer from same problem as #2210
res1 =:= res2.substSym(tparams2, tparams1))
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) =>
lo1 =:= lo2 && hi1 =:= hi2
@@ -3696,7 +3709,7 @@ A type's typeSymbol should never be inspected directly.
res1 <:< res2.substSym(tparams2, tparams1)
case (tp1a, tp2a) =>
- (isDifferentType(tp1a, tp1) || isDifferentType(tp2a, tp2)) &&
+ (isDifferentTypeConstructor(tp1a, tp1) || isDifferentTypeConstructor(tp2a, tp2)) &&
isSubType(tp1a, tp2a, depth)
}))
@@ -3801,7 +3814,7 @@ A type's typeSymbol should never be inspected directly.
isSubType(tp1.normalize, tp2.normalize, depth)
} else if (sym2.isAbstractType) {
val tp2a = tp2.bounds.lo
- isDifferentType(tp2, tp2a) && tp1 <:< tp2a || fourthTry
+ isDifferentTypeConstructor(tp2, tp2a) && tp1 <:< tp2a || fourthTry
} else if (sym2 == NotNullClass) {
tp1.isNotNull
} else if (sym2 == SingletonClass) {
@@ -3868,7 +3881,7 @@ A type's typeSymbol should never be inspected directly.
isSubType(tp1.normalize, tp2.normalize, depth)
} else if (sym1.isAbstractType) {
val tp1a = tp1.bounds.hi
- isDifferentType(tp1, tp1a) && tp1a <:< tp2
+ isDifferentTypeConstructor(tp1, tp1a) && tp1a <:< tp2
} else if (sym1 == NothingClass) {
true
} else if (sym1 == NullClass) {
@@ -3919,7 +3932,6 @@ A type's typeSymbol should never be inspected directly.
case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2))
if !(tp1.isHigherKinded || tp2.isHigherKinded) =>
//Console.println("isSubType " + tp1 + " " + tp2);//DEBUG
-
def isSubArgs(tps1: List[Type], tps2: List[Type],
tparams: List[Symbol]): Boolean = (
tps1.isEmpty && tps2.isEmpty
@@ -3933,9 +3945,9 @@ A type's typeSymbol should never be inspected directly.
else (sym1.name == sym2.name) && isUnifiable(pre1, pre2)) &&
(sym2 == AnyClass || isSubArgs(args1, args2, sym1.typeParams)) //@M: Any is kind-polymorphic
||
- sym1.isAbstractType && isDifferentType(tp1, tp1.bounds.hi) && (tp1.bounds.hi <:< tp2)
+ sym1.isAbstractType && isDifferentTypeConstructor(tp1, tp1.bounds.hi) && (tp1.bounds.hi <:< tp2)
||
- sym2.isAbstractType && isDifferentType(tp2, tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo)
+ sym2.isAbstractType && isDifferentTypeConstructor(tp2, tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo)
||
sym2.isClass &&
({ val base = tp1 baseType sym2; !(base eq tp1) && (base <:< tp2) })
@@ -3989,7 +4001,7 @@ A type's typeSymbol should never be inspected directly.
isSubType0(tp1a, tp2a, depth)
})
case (_, TypeRef(pre2, sym2, args2))
- if (sym2.isAbstractType && isDifferentType(tp2, tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo) ||
+ if (sym2.isAbstractType && isDifferentTypeConstructor(tp2, tp2.bounds.lo) && (tp1 <:< tp2.bounds.lo) ||
sym2 == NotNullClass && tp1.isNotNull) =>
true
case (_, TypeRef(pre2, sym2, args2))