diff options
author | Martin Odersky <odersky@gmail.com> | 2009-02-16 14:56:54 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-02-16 14:56:54 +0000 |
commit | c25ec632d37c8c676e72da5ae792d02be7583232 (patch) | |
tree | bf8711d91d99ca7acb8b10b98c15cb8d92a3edd6 | |
parent | dd368937571ef308989e1388b08e04f55b0b6cd4 (diff) | |
download | scala-c25ec632d37c8c676e72da5ae792d02be7583232.tar.gz scala-c25ec632d37c8c676e72da5ae792d02be7583232.tar.bz2 scala-c25ec632d37c8c676e72da5ae792d02be7583232.zip |
hopefully fixed the build by fixing deSkolemize...
hopefully fixed the build by fixing deSkolemize, and adapting the new
collection libraries to stricter override checking.
12 files changed, 145 insertions, 83 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 6e648371ea..cd51fbce5f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -21,28 +21,27 @@ trait Namers { self: Analyzer => import definitions._ import posAssigner.atPos - /** Convert to corresponding type parameters all skolems which satisfy one - * of the following two conditions: - * 1. The skolem is a parameter of a class or alias type - * 2. The skolem is a method parameter which appears in parameter `tparams' + /** Convert to corresponding type parameters all skolems of method parameters + * which appear in `tparams`. */ class DeSkolemizeMap(tparams: List[Symbol]) extends TypeMap { - def apply(tp: Type): Type = if (tparams.isEmpty) tp - else { - tp match { - case TypeRef(pre, sym, args) - if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) => - mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args)) - case PolyType(tparams1, restpe) => - new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp) - case ClassInfoType(parents, decls, clazz) => - val parents1 = List.mapConserve(parents)(this) + def apply(tp: Type): Type = tp match { + case TypeRef(pre, sym, args) + if (sym.isTypeSkolem && (tparams contains sym.deSkolemize)) => +// println("DESKOLEMIZING "+sym+" in "+sym.owner) + mapOver(rawTypeRef(NoPrefix, sym.deSkolemize, args)) +/* + case PolyType(tparams1, restpe) => + new DeSkolemizeMap(tparams1 ::: tparams).mapOver(tp) + case ClassInfoType(parents, decls, clazz) => + val parents1 = List.mapConserve(parents)(this) if (parents1 eq parents) tp else ClassInfoType(parents1, decls, clazz) - case _ => - mapOver(tp) - } +*/ + case _ => + mapOver(tp) } } + private class NormalNamer(context : Context) extends Namer(context) def newNamer(context : Context) : Namer = new NormalNamer(context) @@ -273,8 +272,9 @@ trait Namers { self: Analyzer => tskolems foreach (_.setInfo(ltp)) tskolems } + /** Replace type parameters with their TypeSkolems, which can later be deskolemized to the original type param - * (a skolem is a representation of a bound variable when viewed outside its scope) + * (a skolem is a representation of a bound variable when viewed inside its scope) */ def skolemize(tparams: List[TypeDef]) { val tskolems = newTypeSkolems(tparams map (_.symbol)) @@ -286,9 +286,6 @@ trait Namers { self: Analyzer => else if (owner.isTerm || owner.isPackageClass) List() else applicableTypeParams(owner.owner) ::: owner.typeParams - def deSkolemize: TypeMap = new DeSkolemizeMap(applicableTypeParams(context.owner)) - // should be special path for IDE but maybe not.... - def enterSym(tree: Tree): Context = try { def finishWith(tparams: List[TypeDef]) { @@ -921,7 +918,26 @@ trait Namers { self: Analyzer => typer.reportTypeError(tree.pos, ex) ErrorType } - deSkolemize(result) + result match { + case PolyType(tparams, restpe) + if (!tparams.isEmpty && tparams.head.owner.isTerm || + // Adriaan: The added conditon below is quite a hack. It seems that HK type parameters is relying + // on a pass that forces all infos in the type to get everything right. + // The problem is that the same pass causes cyclic reference errors in + // test pos/cyclics.scala. It turned out that deSkolemize is run way more often than necessary, + // ruinning it only when needed fixes the cuclic reference errors. + // But correcting deSkolemize broke HK types, because we don't do the traversal anymore. + // For the moment I made a special hack to do the traversal if we have HK type parameters. + // Maybe it's not a hack, then we need to document it better. But ideally, we should find + // a way to deal with HK types that's not dependent on accidental side + // effects like this. + tparams.exists(!_.typeParams.isEmpty)) => + new DeSkolemizeMap(tparams) mapOver result + case _ => +// println("not skolemizing "+result+" in "+context.owner) +// new DeSkolemizeMap(List()) mapOver result + result + } } /** Check that symbol's definition is well-formed. This means: diff --git a/src/library/scalax/collection/generic/MutableVectorView.scala b/src/library/scalax/collection/generic/MutableVectorView.scala index 450943f61d..d445ba336e 100755 --- a/src/library/scalax/collection/generic/MutableVectorView.scala +++ b/src/library/scalax/collection/generic/MutableVectorView.scala @@ -25,6 +25,8 @@ self => /** refined from Iterable.View */ val origin: Vector[_] + override def newBuilder[A] = underlying.newBuilder[A].asInstanceOf[Builder[Vector, A]] + trait Transformed[B] extends super.Transformed[B] with MutableVectorView[UC, B] { override val origin = self override def elements: Iterator[B] = new Elements(0, length) diff --git a/src/library/scalax/collection/generic/OrderedIterableView.scala b/src/library/scalax/collection/generic/OrderedIterableView.scala index fd04daa0b6..9f0d981f54 100755 --- a/src/library/scalax/collection/generic/OrderedIterableView.scala +++ b/src/library/scalax/collection/generic/OrderedIterableView.scala @@ -19,6 +19,8 @@ trait OrderedIterableView[+UC[/*+*/B] <: Iterable[B], /*+*/A] extends IterableVi val origin: OrderedIterable[_] + override def newBuilder[A] = underlying.newBuilder[A].asInstanceOf[Builder[OrderedIterable, A]] + /** Builds a new view object. This method needs to be overridden in subclasses * which refine in IterableView type */ diff --git a/src/library/scalax/collection/generic/SequenceView.scala b/src/library/scalax/collection/generic/SequenceView.scala index aa6f1e50f8..4f70f8a9d8 100755 --- a/src/library/scalax/collection/generic/SequenceView.scala +++ b/src/library/scalax/collection/generic/SequenceView.scala @@ -27,6 +27,8 @@ self => /** refined from Iterable.View */ val origin: Sequence[_] + override def newBuilder[A] = underlying.newBuilder[A].asInstanceOf[Builder[Sequence, A]] + trait Transformed[/*+*/B] extends SequenceView[UC, B] { val origin = self protected def asCC = asInstanceOf[SequenceView[UC, B]] diff --git a/src/library/scalax/collection/generic/covartest/SequenceView.scala b/src/library/scalax/collection/generic/covartest/SequenceView.scala index 77b06b0b4f..e99ffaf652 100755 --- a/src/library/scalax/collection/generic/covartest/SequenceView.scala +++ b/src/library/scalax/collection/generic/covartest/SequenceView.scala @@ -27,6 +27,8 @@ self => /** refined from Iterable.View */ val origin: Sequence[_] + override def newBuilder[A] = underlying.newBuilder[A].asInstanceOf[Builder[Sequence, A]] + trait Transformed[+B] extends SequenceView[UC, B] { val origin = self protected def asCC = asInstanceOf[SequenceView[UC, B]] diff --git a/src/library/scalax/collection/immutable/HashMap.scala b/src/library/scalax/collection/immutable/HashMap.scala index 7d3595904d..8aaa0239c1 100644 --- a/src/library/scalax/collection/immutable/HashMap.scala +++ b/src/library/scalax/collection/immutable/HashMap.scala @@ -37,15 +37,17 @@ object HashMap extends MapFactory[HashMap] { @serializable class HashMap[A, B] extends Map[A,B] with MapTemplate[A, B, HashMap] - with mutable.HashTable[A] { + with collection.mutable.HashTable[A] { - type Entry = mutable.DefaultEntry[A, Any] + type Entry = collection.mutable.DefaultEntry[A, Any] protected var later: HashMap[A, B] = null protected var oldKey: A = _ protected var oldValue: Option[B] = _ protected var deltaSize: Int = _ + override def empty[B] = HashMap.empty[A, B] + def get(key: A): Option[B] = synchronized { var m = this var cnt = 0 @@ -141,7 +143,7 @@ class HashMap[A, B] extends Map[A,B] } val ltable = last.table val s = ltable.length - table = new scala.Array[mutable.HashEntry[A, Entry]](s) + table = new scala.Array[collection.mutable.HashEntry[A, Entry]](s) var i = 0 while (i < s) { table(i) = copy(ltable(i).asInstanceOf[Entry]) diff --git a/src/library/scalax/collection/mutable/ArrayBuffer.scala b/src/library/scalax/collection/mutable/ArrayBuffer.scala index daf514c485..1692280e21 100644 --- a/src/library/scalax/collection/mutable/ArrayBuffer.scala +++ b/src/library/scalax/collection/mutable/ArrayBuffer.scala @@ -39,6 +39,8 @@ class ArrayBuffer[A](override protected val initialSize: Int) def clear() { reduceToSize(0) } + override def newBuilder[B]: Builder[ArrayBuffer, B] = new ArrayBuffer[B] + /** Appends a single element to this buffer and returns * the identity of the buffer. It takes constant time. * diff --git a/src/library/scalax/collection/mutable/ListBuffer.scala b/src/library/scalax/collection/mutable/ListBuffer.scala index 4d0ad7ec80..faf897aef2 100644 --- a/src/library/scalax/collection/mutable/ListBuffer.scala +++ b/src/library/scalax/collection/mutable/ListBuffer.scala @@ -41,9 +41,17 @@ final class ListBuffer[A] private var start: List[A] = Nil private var last0: ::[A] = _ private var exported: Boolean = false + private var len = 0 protected def underlying: Sequence[A] = start + override def newBuilder[B]: Builder[ListBuffer, B] = + new AddableBuilder[ListBuffer, B](new ListBuffer[B]) // !!! Adriaan: inference failure here + + /** The current length of the buffer + */ + override def length = len + // Implementations of abstract methods in Buffer /** Replaces element at index <code>n</code> with the new element @@ -59,7 +67,10 @@ final class ListBuffer[A] if (exported) copy() if (n == 0) { val newElem = new :: (x, start.tail); - if (last0 eq start) last0 = newElem + if (last0 eq start) { + last0 = newElem + len += 1 + } start = newElem } else { var cursor = start @@ -69,7 +80,10 @@ final class ListBuffer[A] i += 1 } val newElem = new :: (x, cursor.tail.tail) - if (last0 eq cursor.tail) last0 = newElem + if (last0 eq cursor.tail) { + last0 = newElem + len += 1 + } cursor.asInstanceOf[::[A]].tl = newElem } } catch { @@ -91,6 +105,7 @@ final class ListBuffer[A] last0 = new :: (x, Nil) last1.tl = last0 } + len += 1 } /** Clears the buffer contents. @@ -98,6 +113,7 @@ final class ListBuffer[A] def clear() { start = Nil exported = false + len = 0 } /** Prepends a single element to this buffer. This operation takes constant @@ -111,6 +127,7 @@ final class ListBuffer[A] val newElem = new :: (x, start) if (start.isEmpty) last0 = newElem start = newElem + len += 1 this } @@ -126,6 +143,7 @@ final class ListBuffer[A] try { if (exported) copy() var elems = iter.elements.toList.reverse + len += elems.length if (n == 0) { while (!elems.isEmpty) { val newElem = new :: (elems.head, start) @@ -153,42 +171,39 @@ final class ListBuffer[A] } } - /** Removes the element on a given index position. This operation takes time linear in + /** Removes a given number of elements on a given index position. May take time linear in * the buffer size. * - * @param n the index which refers to the element to delete. - * @return the updated array buffer. - * @throws Predef.IndexOutOfBoundsException if <code>n</code> is out of bounds. + * @param n the index which refers to the first element to remove. + * @param count the number of elements to remove. */ def remove(n: Int, count: Int) { - try { - if (exported) copy() - var old = start.head; - if (n == 0) { - var c = count - while (c > 0) { - start = start.tail - c -= 1 - } - } else { - var cursor = start - var i = 1 - while (i < n) { - cursor = cursor.tail - i += 1 - } - var c = count - while (c > 0) { - if (last0 eq cursor.tail) last0 = cursor.asInstanceOf[::[A]] - cursor.asInstanceOf[::[A]].tl = cursor.tail.tail - c -= 1 - } + if (exported) copy() + val n1 = n max 0 + val count1 = count min (len - n1) + var old = start.head; + if (n1 == 0) { + var c = count1 + while (c > 0) { + start = start.tail + c -= 1 } - old - } catch { - case ex: Exception => - throw new IndexOutOfBoundsException(n.toString()) - } } + } else { + var cursor = start + var i = 1 + while (i < n1) { + cursor = cursor.tail + i += 1 + } + var c = count1 + while (c > 0) { + if (last0 eq cursor.tail) last0 = cursor.asInstanceOf[::[A]] + cursor.asInstanceOf[::[A]].tl = cursor.tail.tail + c -= 1 + } + } + len -= count1 + } // Implementation of abstract method in Builder @@ -214,9 +229,8 @@ final class ListBuffer[A] // Overrides of methods in Buffer - /** Removes the element on a given index position. Takes time linear in - * the buffer size (except for the first element, which is removed in constant - * time). + /** Removes the element on a given index position. May take time linear in + * the buffer size * * @param n the index which refers to the element to delete. * @return n the element that was formerly at position <code>n</code>. @@ -224,6 +238,7 @@ final class ListBuffer[A] * @throws Predef.IndexOutOfBoundsException if <code>n</code> is out of bounds. */ override def remove(n: Int): A = try { + if (n < 0 || n >= len) throw new IndexOutOfBoundsException(n.toString()) if (exported) copy() var old = start.head; if (n == 0) { @@ -239,29 +254,31 @@ final class ListBuffer[A] if (last0 eq cursor.tail) last0 = cursor.asInstanceOf[::[A]] cursor.asInstanceOf[::[A]].tl = cursor.tail.tail } + len -= 1 old - } catch { - case ex: Exception => - throw new IndexOutOfBoundsException(n.toString()) } - /** Remove a single element from this buffer. This operation takes linear time - * (except removing the first element, which is done in constant time). + /** Remove a single element from this buffer. May take time linear in the buffer size. * * @param x the element to remove. */ - override def -= (x: A) { + override def -= (elem: A) { if (exported) copy() if (start.isEmpty) {} - else if (start.head == x) start = start.tail - else { + else if (start.head == elem) { + start = start.tail + len -= 1 + } else { var cursor = start - while (!cursor.tail.isEmpty && cursor.tail.head != x) { cursor = cursor.tail } + while (!cursor.tail.isEmpty && cursor.tail.head != elem) { + cursor = cursor.tail + } if (!cursor.tail.isEmpty) { val z = cursor.asInstanceOf[::[A]] if (z.tl == last0) last0 = z z.tl = cursor.tail.tail + len -= 1 } } } diff --git a/src/library/scalax/collection/mutable/Map.scala b/src/library/scalax/collection/mutable/Map.scala index 43f42df298..82fb6a5680 100755 --- a/src/library/scalax/collection/mutable/Map.scala +++ b/src/library/scalax/collection/mutable/Map.scala @@ -26,8 +26,6 @@ trait Map[A, B] with Cloneable[Map[A, B]] { self => - override def thisCC: Map[A, B] = this - /** This method allows one to add a new mapping from <code>key</code> * to <code>value</code> to the map. If the map already contains a * mapping for <code>key</code>, it will be overridden by this diff --git a/test/files/neg/bug692.check b/test/files/neg/bug692.check index 099a261f42..14df1917d9 100644 --- a/test/files/neg/bug692.check +++ b/test/files/neg/bug692.check @@ -1,19 +1,19 @@ bug692.scala:3: error: not found: type T - trait Type[T0] extends Type0[T];
+ trait Type[T0] extends Type0[T]; ^ bug692.scala:10: error: class Foo takes type parameters - case class FooType() extends ClassType[Foo,AnyRef](ObjectType());
+ case class FooType() extends ClassType[Foo,AnyRef](ObjectType()); ^ bug692.scala:13: error: class Foo takes type parameters - case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
+ case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType); ^ bug692.scala:13: error: class Foo takes type parameters - case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType);
+ case class BarType[T3 <: Foo](tpeT : RefType[T3]) extends ClassType[Bar[T3],Foo](FooType); ^ -bug692.scala:19: error: class Foo takes type parameters - class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo;
- ^ bug692.scala:14: error: class Foo takes type parameters - implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] =
+ implicit def typeOfBar[T4 <: Foo](implicit elem : RefType[T4]) : RefType[Bar[T4]] = ^ +bug692.scala:19: error: class Foo takes type parameters + class Bar[A <: Foo](implicit tpeA : Type[A]) extends Foo; + ^ 6 errors found diff --git a/test/files/pos/cyclics.scala b/test/files/pos/cyclics.scala index 69092ce7ab..a49f4faaca 100644 --- a/test/files/pos/cyclics.scala +++ b/test/files/pos/cyclics.scala @@ -1,7 +1,26 @@ trait Param[T] trait Abs { type T } trait Cyclic1[A <: Param[A]] // works -trait Cyclic2[A <: Abs { type T <: A }] // fails -trait Cyclic3 { type A <: Abs { type T = A } } // fails +trait Cyclic2[A <: Abs { type T <: A }] +trait Cyclic3 { type A <: Abs { type T = A } } trait Cyclic4 { type A <: Param[A] } // works +trait Cyclic5 { type AA <: Abs; type A <: AA { type T = A } } + +trait IterableTemplate { + type Elem + type Constr <: IterableTemplate + type ConstrOf[A] = Constr { type Elem = A } + + def elements: Iterator[Elem] + + def map [B] (f: Elem => B): ConstrOf[B] + + def foreach(f: Elem => Unit) = elements.foreach(f) +} + + +trait Iterable[A] extends IterableTemplate { self => + type Elem + type Constr <: Iterable[A] { type Constr <: Iterable.this.Constr } +} diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index c8f0a83ad3..d3c32b7a02 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -85,7 +85,7 @@ defined class peer ----- class NPE[T <: NPE[T] @peer] // should not crash -error: illegal cyclic reference involving class NPE +defined class NPE ----- def m = { |