diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2009-08-13 08:37:24 +0000 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2009-08-13 08:37:24 +0000 |
commit | 2416d5724eb7fba3ed5b80092194a27e333a23f3 (patch) | |
tree | 6432d8e90ca5c1ed1b6c65798ee06679f70b6735 /src | |
parent | 1ceff6729ae30c61ec43e615daf9ef96ea59aae7 (diff) | |
download | scala-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.scala | 72 |
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)) |