summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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))