diff options
author | Martin Odersky <odersky@gmail.com> | 2007-07-24 17:43:47 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2007-07-24 17:43:47 +0000 |
commit | 5355f3c7323fa0ea1dabe2e39ec112c9d0b061b9 (patch) | |
tree | 2bda3cd539639ca5387a2a2fcea922a4c7ee480a | |
parent | d8504784b821fb64f411adf7c551ee4646e5f99c (diff) | |
download | scala-5355f3c7323fa0ea1dabe2e39ec112c9d0b061b9.tar.gz scala-5355f3c7323fa0ea1dabe2e39ec112c9d0b061b9.tar.bz2 scala-5355f3c7323fa0ea1dabe2e39ec112c9d0b061b9.zip |
fixed problems in subtyping.
fixed unsafe isInstanceOf's
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Types.scala | 114 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/ListSet.scala | 9 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/Stack.scala | 6 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/LinkedList.scala | 7 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/PriorityQueue.scala | 12 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/Queue.scala | 12 | ||||
-rw-r--r-- | src/library/scala/collection/mutable/Stack.scala | 12 | ||||
-rw-r--r-- | src/library/scala/reflect/Print.scala | 24 | ||||
-rw-r--r-- | src/library/scala/xml/Utility.scala | 5 | ||||
-rwxr-xr-x | test/files/run/bug1220.scala | 14 |
15 files changed, 163 insertions, 73 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 68a34def62..eb176dca42 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1159,7 +1159,7 @@ trait Parsers { case USCORE => val pname = freshName("x$") val pos = inSkipToken - val param = makeSyntheticParam(pname) setPos pos + val param = atPos(pos){ makeSyntheticParam(pname) } placeholderParams = param :: placeholderParams t = atPos(pos) { Ident(pname) } case LPAREN => diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 57c8e4e60b..55aa36c510 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1389,8 +1389,10 @@ A type's typeSymbol should never be inspected directly. if (isTupleType(this)) return args.mkString("(", ", ", if (args.length == 1) ",)" else ")") } - val str = (pre.prefixString + sym.nameString + + var str = (pre.prefixString + sym.nameString + (if (args.isEmpty) "" else args.mkString("[", ",", "]"))) + //if (sym.nameString startsWith "moduleType") + // str += ("_in_"+sym.ownerChain) if (sym.isPackageClass) packagePrefix + str else if (sym.isModuleClass) @@ -1574,8 +1576,9 @@ A type's typeSymbol should never be inspected directly. /** A class representing a type variable * Not used after phase `typer'. */ - case class TypeVar(origin: Type, constr: TypeConstraint) extends Type { + case class TypeVar(origin: Type, constr0: TypeConstraint) extends Type { //constr.self = this //DEBUG + var constr = constr0 override def typeSymbol = origin.typeSymbol @deprecated override def symbol = origin.symbol override def toString: String = @@ -1941,14 +1944,12 @@ A type's typeSymbol should never be inspected directly. var lobounds: List[Type] = lo var hibounds: List[Type] = hi var inst: Type = NoType -/* debug - private var _inst: Type = NoType - def inst = _inst - def inst_=(tp: Type) { - assert(tp == null || !(tp containsTp self), tp) - _inst = tp + + def duplicate = { + val tc = new TypeConstraint(lo, hi) + tc.inst = inst + tc } -*/ def instantiate(tp: Type): Boolean = if (lobounds.forall(_ <:< tp) && hibounds.forall(tp <:< _)) { @@ -2602,6 +2603,12 @@ A type's typeSymbol should never be inspected directly. } } + var undoLog: List[(TypeVar, TypeConstraint)] = List() + + def snapShot(tv: TypeVar) { + undoLog = (tv, tv.constr.duplicate) :: undoLog + } + /** Do `tp1' and `tp2' denote equivalent types? * * @param tp1 ... @@ -2687,12 +2694,12 @@ A type's typeSymbol should never be inspected directly. bounds containsType tp2 case (_, BoundedWildcardType(bounds)) => bounds containsType tp1 - case (TypeVar(_, constr1), _) => + case (tv1 @ TypeVar(_, constr1), _) => if (constr1.inst != NoType) constr1.inst =:= tp2 - else constr1 instantiate (wildcardToTypeVarMap(tp2)) - case (_, TypeVar(_, constr2)) => + else { snapShot(tv1); constr1 instantiate wildcardToTypeVarMap(tp2) } + case (_, tv2 @ TypeVar(_, constr2)) => if (constr2.inst != NoType) tp1 =:= constr2.inst - else constr2 instantiate (wildcardToTypeVarMap(tp1)) + else { snapShot(tv2); constr2 instantiate wildcardToTypeVarMap(tp1) } case (AnnotatedType(_,atp), _) => isSameType(atp, tp2) case (_, AnnotatedType(_,atp)) => @@ -2725,27 +2732,58 @@ A type's typeSymbol should never be inspected directly. def isSubType(tp1: Type, tp2: Type): Boolean = try { stc = stc + 1 - if (stc >= LogPendingSubTypesThreshold) { - val p = new SubTypePair(tp1, tp2) - if (pendingSubTypes contains p) - false - else - try { - pendingSubTypes += p - isSubType0(tp1, tp2) - } finally { - pendingSubTypes -= p - } - } else { - isSubType0(tp1, tp2) + val lastUndoLog = undoLog + val result = + if (stc >= LogPendingSubTypesThreshold) { + val p = new SubTypePair(tp1, tp2) + if (pendingSubTypes contains p) + false + else + try { + pendingSubTypes += p + isSubType0(tp1, tp2) + } finally { + pendingSubTypes -= p + } + } else { + isSubType0(tp1, tp2) + } + if (!result) { + while (undoLog ne lastUndoLog) { + val (tv, constr) = undoLog.head + undoLog = undoLog.tail + tv.constr = constr + } } + result } finally { stc = stc - 1 + if (stc == 0) undoLog = List() } /** hook for IDE */ protected def trackTypeIDE(sym : Symbol) : Boolean = true; + def isTypeVar(tp: Type): Boolean = tp match { + case SingleType(pre, sym) => + !(sym hasFlag PACKAGE) && isTypeVar(pre) + case TypeVar(_, constr) => + constr.inst == NoType || isTypeVar(constr.inst) + case _ => + false + } + + def instTypeVar(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) => + typeRef(instTypeVar(pre), sym, args) + case SingleType(pre, sym) => + singleType(instTypeVar(pre), sym) + case TypeVar(_, constr) => + instTypeVar(constr.inst) + case _ => + tp + } + /** Does type `tp1' conform to `tp2'? * * @param tp1 ... @@ -2785,8 +2823,16 @@ A type's typeSymbol should never be inspected directly. isSubArgs(tps1.tail, tps2.tail, tparams.tail) ); (sym1 == sym2 && - (phase.erasedTypes || pre1 <:< pre2) && - (sym2 == AnyClass || isSubArgs(args1, args2, sym1.typeParams)) //@M: Any is kind-polymorphic + (phase.erasedTypes || pre1 <:< pre2) && + (sym2 == AnyClass || isSubArgs(args1, args2, sym1.typeParams)) //@M: Any is kind-polymorphic +/* + || + sym1.name == sym2.name && +// (sym1.owner isSubClass sym2.owner) && + (isTypeVar(pre1) || isTypeVar(pre2)) && + pre1 =:= pre2 && + instTypeVar(tp1) <:< instTypeVar(tp2) +*/ || sym1.isAbstractType && !(tp1 =:= tp1.bounds.hi) && (tp1.bounds.hi <:< tp2) || @@ -2816,12 +2862,12 @@ A type's typeSymbol should never be inspected directly. bounds.lo <:< tp2 case (_, BoundedWildcardType(bounds)) => tp1 <:< bounds.hi - case (_, TypeVar(_, constr2)) => + case (_, tv2 @ TypeVar(_, constr2)) => if (constr2.inst != NoType) tp1 <:< constr2.inst - else { constr2.lobounds = tp1 :: constr2.lobounds; true } - case (TypeVar(_, constr1), _) => + else { snapShot(tv2); constr2.lobounds = tp1 :: constr2.lobounds; true } + case (tv1 @ TypeVar(_, constr1), _) => if (constr1.inst != NoType) constr1.inst <:< tp2 - else { constr1.hibounds = tp2 :: constr1.hibounds; true } + else { snapShot(tv1); constr1.hibounds = tp2 :: constr1.hibounds; true } case (AnnotatedType(_,atp1), _) => atp1 <:< tp2 case (_, AnnotatedType(_,atp2)) => @@ -2848,9 +2894,9 @@ A type's typeSymbol should never be inspected directly. val tvars = tparams2 map (tparam => new TypeVar(tparam.tpe, new TypeConstraint)) val ires2 = res2.instantiateTypeParams(tparams2, tvars) (tp1 <:< ires2) && { -// println("solve: "+tparams2) + //println("solve: "+tparams2) solve(tvars, tparams2, tparams2 map (x => 0), false) -// println("check bounds: "+tparams2+" aginst "+(tvars map (_.constr.inst))) + //println("check bounds: "+tparams2+" aginst "+(tvars map (_.constr.inst))) isWithinBounds(NoPrefix, NoSymbol, tparams2, tvars map (_.constr.inst)) } case (RefinedType(parents1, ref1), _) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index a18e2b80eb..8acb9173af 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -490,13 +490,15 @@ trait Infer { () } val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), false) +// val res = List.map2(tparams, targs) {(tparam, targ) => if (targ.typeSymbol == AllClass && (varianceInType(restpe)(tparam) & COVARIANT) == 0) { uninstantiated += tparam tparam.tpe //@M TODO: might be affected by change to tpe in Symbol } else targ.widen } -// println("meth type args "+", tparams = "+tparams+", formals = "+formals+", restpe = "+restpe+", argtpes = "+argtpes+", underlying = "+(argtpes map (_.widen))+", pt = "+pt+", uninstantiated = "+uninstantiated.toList+", result = "+res) //DEBUG +// println("meth type args "+", tparams = "+tparams+", formals = "+formals+", restpe = "+restpe+", argtpes = "+argtpes+", underlying = "+(argtpes map (_.widen))+", pt = "+pt+", uninstantiated = "+uninstantiated.toList+", result = "+res) //DEBUG +// res } /** Is there an instantiation of free type variables <code>undetparams</code> diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 8bbc88c390..ff24719b18 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -358,6 +358,18 @@ trait Namers { self: Analyzer => override def complete(sym: Symbol) { if (settings.debug.value) log("defining " + sym + Flags.flagsToString(sym.flags)); val tp = typeSig(tree) + // check that + tp match { + case TypeBounds(lo, hi) => + // check that lower bound is not an F-bound + for (val t <- lo) { + t match { + case TypeRef(_, sym, _) => sym.initialize + case _ => + } + } + case _ => + } sym.setInfo(tp) if ((sym.isAliasType || sym.isAbstractType) && !(sym hasFlag PARAM) && !typer.checkNonCyclic(tree.pos, tp)) diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala index aac29e8875..dc05fc32ba 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala @@ -21,6 +21,7 @@ abstract class TreeCheckers extends Analyzer { } def check(unit: CompilationUnit) { + informProgress("checking "+unit) val context = rootContext(unit) context.checking = true tpeOfTree.clear diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 0fee0c07dc..bed72e52a9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1302,7 +1302,7 @@ trait Typers { self: Analyzer => var body1: Tree = typed(cdef.body, pt) if (!context.savedTypeBounds.isEmpty) { body1.tpe = context.restoreTypeBounds(body1.tpe) - if (isFullyDefined(pt)) + if (isFullyDefined(pt) && !(body1.tpe <:< pt)) // the following is a hack to make the pattern matcher work !!! (still needed?) body1 = typed { diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index 6bf4d5b626..3945612143 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -86,12 +86,13 @@ class ListSet[A] extends AnyRef with Set[A] { /** Compares two sets for equality. * Two set are equal iff they contain the same elements. */ - override def equals(obj: Any): Boolean = - if (obj.isInstanceOf[scala.collection.Set[A]]) { + override def equals(obj: Any): Boolean = obj match { + case _: scala.collection.Set[_] => val that = obj.asInstanceOf[scala.collection.Set[A]] - if (size != that.size) false else toList.forall(that.contains) - } else + (size == that.size) && (toList forall that.contains) + case _ => false + } /** * @throws Predef.NoSuchElementException diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala index 22f257b99f..75d6cb8b98 100644 --- a/src/library/scala/collection/immutable/Stack.scala +++ b/src/library/scala/collection/immutable/Stack.scala @@ -106,8 +106,10 @@ class Stack[+A] extends Seq[A] { * @return true, iff the two stacks are equal; i.e. they contain the * same elements in the same order. */ - override def equals(obj: Any): Boolean = - obj.isInstanceOf[Stack[A]] && sameElements(obj.asInstanceOf[Stack[A]]) + override def equals(obj: Any): Boolean = obj match { + case that: Stack[_] => this sameElements that + case _ => false + } /** Returns the hash code for this stack. * diff --git a/src/library/scala/collection/mutable/LinkedList.scala b/src/library/scala/collection/mutable/LinkedList.scala index bd5ae23532..0ed1a02889 100644 --- a/src/library/scala/collection/mutable/LinkedList.scala +++ b/src/library/scala/collection/mutable/LinkedList.scala @@ -22,9 +22,10 @@ class LinkedList[A](var elem: A, var next: LinkedList[A]) extends SingleLinkedList[A, LinkedList[A]] { - override def equals(obj: Any): Boolean = - obj.isInstanceOf[LinkedList[A]] && - toList.equals((obj.asInstanceOf[LinkedList[A]]).toList) + override def equals(obj: Any): Boolean = obj match { + case that: LinkedList[_] => this.toList equals that.toList + case _ => false + } override protected def stringPrefix: String = "LinkedList" } diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index 0772c545e9..de615469d8 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -153,12 +153,14 @@ class PriorityQueue[A <% Ordered[A]] extends ResizableArray[A] with CloneableCol * * @return true, iff both queues contain the same sequence of elements. */ - override def equals(that: Any): Boolean = - that.isInstanceOf[PriorityQueue[A]] && - { val other = that.asInstanceOf[PriorityQueue[A]] - elements.zip(other.elements).forall { + override def equals(obj: Any): Boolean = obj match { + case that: PriorityQueue[_] => + (this.elements zip that.elements) forall { case (thiselem, thatelem) => thiselem == thatelem - }} + } + case _ => + false + } /** The hashCode method always yields an error, since it is not * safe to use mutable queues as keys in hash tables. diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index d654a82888..e7c80ae7b4 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -166,12 +166,14 @@ class Queue[A] extends MutableList[A] with CloneableCollection { * * @return true, iff both queues contain the same sequence of elements. */ - override def equals(that: Any): Boolean = - that.isInstanceOf[Queue[A]] && - { val other = that.asInstanceOf[Queue[A]] - elements.zip(other.elements).forall { + override def equals(obj: Any): Boolean = obj match { + case that: Queue[_] => + (this.elements zip that.elements) forall { case (thiselem, thatelem) => thiselem == thatelem - }} + } + case _ => + false + } /** The hashCode method always yields an error, since it is not * safe to use mutable queues as keys in hash tables. diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index be95aee1a5..8aa2f27115 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -107,12 +107,14 @@ class Stack[A] extends MutableList[A] with CloneableCollection { * * @return true, iff both stacks contain the same sequence of elements. */ - override def equals(that: Any): Boolean = - that.isInstanceOf[Stack[A]] && - { val other = that.asInstanceOf[Stack[A]]; - elements.zip(other.elements).forall { + override def equals(obj: Any): Boolean = obj match { + case that: Stack[_] => + (this.elements zip that.elements) forall { case (thiselem, thatelem) => thiselem == thatelem - }} + } + case _ => + false + } /** The hashCode method always yields an error, since it is not * safe to use mutable stacks as keys in hash tables. diff --git a/src/library/scala/reflect/Print.scala b/src/library/scala/reflect/Print.scala index 789d112490..039160077c 100644 --- a/src/library/scala/reflect/Print.scala +++ b/src/library/scala/reflect/Print.scala @@ -13,18 +13,20 @@ package scala.reflect object Print extends Function1[Any, String] { - def apply(any: Any): String = - if (any.isInstanceOf[Code[Any]]) - apply(any.asInstanceOf[Code[Any]]) - else if (any.isInstanceOf[Tree]) - apply(any.asInstanceOf[Tree]) - else if (any.isInstanceOf[Symbol]) - apply(any.asInstanceOf[Symbol]) - else if (any.isInstanceOf[Type]) - apply(any.asInstanceOf[Type]) - else "UnknownAny" + def apply(any: Any): String = any match { + case x: Code[_] => + apply(x) + case x: Tree => + apply(x) + case x: Symbol => + apply(x) + case x: Type => + apply(x) + case _ => + "UnknownAny" + } - def apply(code: Code[Any]): String = + def apply[A](code: Code[A]): String = Print(code.tree) def apply(tree: Tree): String = tree match { diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 00f93b9ffc..3f3ac9d6e8 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -219,7 +219,10 @@ object Utility extends AnyRef with parsing.TokenTests { sb: StringBuilder, stripComment: Boolean) { if (children.isEmpty) return - else if (children forall { y => y.isInstanceOf[Atom[Any]] && !y.isInstanceOf[Text] }) { // add space + else if (children forall { + case y: Atom[_] => !y.isInstanceOf[Text] + case _ => false + }) { // add space val it = children.elements val f = it.next toXML(f, f.scope, sb, stripComment) diff --git a/test/files/run/bug1220.scala b/test/files/run/bug1220.scala new file mode 100755 index 0000000000..a992e5f2a5 --- /dev/null +++ b/test/files/run/bug1220.scala @@ -0,0 +1,14 @@ +object Test extends Application { + class QSRichIterable[A](self:Iterable[A]) { + def filterMap[R](f: PartialFunction[A,R]) = + self filter (f.isDefinedAt) map f + } + + object Un { + def unapply(i:int): Option[int] = Some(i) + } + + val richIter = new QSRichIterable(List(0, 1, 2, 3, 4)) + + assert((richIter filterMap {case Un(3) => 7}) == List(7)) +} |