From a49cbca4e93d573b0687023d3458bb8a1473e463 Mon Sep 17 00:00:00 2001 From: Sean McDirmid Date: Fri, 19 Oct 2007 12:53:52 +0000 Subject: * Fixed array cast bug in Errasure. * Tweaked GenerateIDEs to have more coverage * Deprecated * in favor of ** for sets --- .../scala/tools/nsc/symtab/Definitions.scala | 5 ++- .../scala/tools/nsc/symtab/GenerateIdeMaps.scala | 23 ++++++++++-- src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + .../nsc/symtab/classfile/ClassfileParser.scala | 4 ++- .../scala/tools/nsc/transform/Erasure.scala | 27 ++++++++++---- .../scala/tools/nsc/typechecker/Typers.scala | 1 + src/library/scala/collection/jcl/ArrayList.scala | 18 +--------- src/library/scala/collection/jcl/Buffer.scala | 25 +++++++++---- .../scala/collection/jcl/BufferIterator.scala | 1 - .../scala/collection/jcl/MutableIterable.scala | 2 +- src/library/scala/collection/jcl/Set.scala | 6 ++-- src/library/scala/collection/mutable/Map.scala | 1 + src/library/scala/runtime/ScalaRunTime.scala | 2 +- test/files/run/array_casts.check | 16 +++++++++ test/files/run/array_casts.scala | 42 ++++++++++++++++++++++ 15 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 test/files/run/array_casts.check create mode 100644 test/files/run/array_casts.scala diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index c9dc436b6d..04bc33e043 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -103,7 +103,10 @@ trait Definitions { def Iterable_hasNext = getMember(IterableClass, nme.hasNext) lazy val IteratorClass: Symbol = getClass("scala.Iterator") lazy val SeqClass: Symbol = getClass("scala.Seq") - def Seq_length = getMember(SeqClass, nme.length) + lazy val RandomAccessSeqMutableClass: Symbol = getMember(getModule("scala.RandomAccessSeq"), nme.Mutable) + def Seq_length = getMember(SeqClass, nme.length) + + lazy val ListClass: Symbol = getClass("scala.List") def List_isEmpty = getMember(ListClass, nme.isEmpty) def List_head = getMember(ListClass, nme.head) diff --git a/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala b/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala index a137ed7490..0aa900529a 100644 --- a/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala +++ b/src/compiler/scala/tools/nsc/symtab/GenerateIdeMaps.scala @@ -335,7 +335,23 @@ abstract class GenerateIdeMaps extends SubComponent { dup.tpe = tree.tpe f(dup) } else f(tree.ref) - case tree : SelectFromTypeTree => f(tree.qualifier) + case tree : CompoundTypeTree => f(tree.templ) + case tree : Template => fs(tree.parents); f(tree.self); fs(tree.body) + case tree : SelectFromTypeTree => { + if (tree.qualifier.tpe == null) tree.tpe match { + case tpe : TypeRef => + // give it a type! + tree.qualifier.tpe = tpe.prefix + case _ => + // tree.tpe.pre + } + f(tree.qualifier) + } + case tree : Literal => + if (tree.tpe != null && tree.tpe.typeSymbol == definitions.ClassClass) { + // nothing we can do without original tree. + } + case tree : Typed => f(tree.expr); f(tree.tpt) case tree : Block => fs(tree.stats); f(tree.expr) case tree: CaseDef => f(tree.pat);f(tree.guard);f(tree.body) @@ -392,8 +408,9 @@ abstract class GenerateIdeMaps extends SubComponent { if (sym.linkedModuleOfClass eq NoSymbol) { if (isRoot(sym.owner)) { return sym.name.toString - } - throw new Error(sym + " " + sym.moduleClass + " " + sym.isPackage + " " + sym.owner) + } else if (sym.owner != NoSymbol) return sym2url(sym.owner) + "." + sym.name.toString + Console.println("XXX: " + sym + " " + sym.moduleClass + " " + sym.isPackage + " " + sym.owner) + return sym.name.toString } return sym2url(sym.linkedModuleOfClass) } diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index ed3348e838..105a6466d4 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -296,6 +296,7 @@ trait StdNames { val lengthCompare = newTermName("lengthCompare") val lift_ = newTermName("lift") val map = newTermName("map") + val Mutable = newTypeName("Mutable") val n = newTermName("n") val ne = newTermName("ne") val nobinding = newTermName("nobinding") diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 6031aeec16..06209194b7 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -330,7 +330,9 @@ abstract class ClassfileParser { val c = pool.getClassSymbol(in.nextChar) if (c != clazz) { assert(true) - throw new IOException("class file '" + in.file + "' contains wrong " + c) + if (inIDE) { + Console.println("WRONG CLASS: expected: " + clazz + " found " + c) + } else throw new IOException("class file '" + in.file + "' contains wrong " + c) } val superType = if (isAnnotation) { in.nextChar; definitions.AnnotationClass.tpe } else pool.getSuperClass(in.nextChar).tpe diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index a2575e59ad..8e6e315f7d 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -180,6 +180,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { private def isSeqClass(sym: Symbol) = (SeqClass isNonBottomSubClass sym) && (sym != ObjectClass) + /** Decides if sym is a supertype of array, right now that includes + from RandomAccessSeq.Mutable */ + private def isArraySuper(sym: Symbol) = + (RandomAccessSeqMutableClass isNonBottomSubClass sym) //&& (sym != ObjectClass) + // -------- boxing/unboxing -------------------------------------------------------- override def newTyper(context: Context) = new Eraser(context) @@ -277,8 +282,8 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { private def cast(tree: Tree, pt: Type): Tree = { assert(pt eq pt.normalize) - if (tree.tpe.typeSymbol == ObjectClass) { - if (pt.typeSymbol == ArrayClass) + if (isArraySuper(tree.tpe.typeSymbol)) { // == ObjectClass) { + if (pt.typeSymbol == ArrayClass) { typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => @@ -295,7 +300,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } } - else if (pt.typeSymbol isNonBottomSubClass BoxedArrayClass) + } else if (pt.typeSymbol isNonBottomSubClass BoxedArrayClass) { typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => @@ -312,7 +317,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } } - else if (isSeqClass(pt.typeSymbol)) + } else if (isArraySuper(pt.typeSymbol)) { typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => @@ -329,7 +334,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } } - else gen.mkAttributedCast(tree, pt) + } else gen.mkAttributedCast(tree, pt) } else gen.mkAttributedCast(tree, pt) } @@ -439,16 +444,18 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { val qual1 = typedQualifier(qual) val qualClass = qual1.tpe.typeSymbol val targClass = targ.tpe.typeSymbol + /* if (isNumericValueClass(qualClass) && isNumericValueClass(targClass)) // convert numeric type casts atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) else */ + assert(true) if (isValueType(targClass) || (targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass))) unbox(qual1, targ.tpe) - else if (targClass == ArrayClass && qualClass == ObjectClass || isSeqClass(targClass)) + else if (((targClass == ArrayClass || isArraySuper(targClass)) && isArraySuper(qualClass))) cast(qual1, targ.tpe) else tree @@ -825,7 +832,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } case _ => - if (isSeqClass(targ.tpe.typeSymbol)) { + if (isArraySuper(targ.tpe.typeSymbol)) { atPos(tree.pos) { gen.evalOnce(qual, currentOwner, unit) { q => gen.mkOr( @@ -835,6 +842,12 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { }) } } + } else if (isArraySuper(qual.tpe.typeSymbol) && targ.tpe.typeSymbol == ArrayClass) { + gen.evalOnce(qual, currentOwner, unit) { q => + atPos(tree.pos) { + Apply(gen.mkAttributedRef(isArrayMethod), List(q())) + } + } } else tree } case _ => tree diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ef07b183f3..9737cc906b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3036,6 +3036,7 @@ trait Typers { self: Analyzer => result } catch { case ex: TypeError => + if (inIDE) throw ex tree.tpe = null //Console.println("caught "+ex+" in typed");//DEBUG reportTypeError(tree.pos, ex) diff --git a/src/library/scala/collection/jcl/ArrayList.scala b/src/library/scala/collection/jcl/ArrayList.scala index 2b433cd059..166dcc7314 100644 --- a/src/library/scala/collection/jcl/ArrayList.scala +++ b/src/library/scala/collection/jcl/ArrayList.scala @@ -14,22 +14,6 @@ package scala.collection.jcl; * * @author Sean McDirmid */ -class ArrayList[A](override val underlying : java.util.ArrayList) extends RandomAccessSeq.Mutable[A] with BufferWrapper[A] { +class ArrayList[A](override val underlying : java.util.ArrayList) extends BufferWrapper[A] { def this() = this(new java.util.ArrayList); - override def elements = super[BufferWrapper].elements; - - trait Projection0[A] extends MutableSeq.Projection[A] with RandomAccessSeq.Projection[A] { - override def projection : Projection0[A] = this - override def elements : SeqIterator[Int,A] = new DefaultSeqIterator - - protected class MapProjection[B](f : A => B) extends super.MapProjection[B](f) with Projection0[B] { - override def projection = this - } - override def map[B](f: A => B) : Projection0[B] = new MapProjection[B](f) - } - class Projection extends Buffer.Projection[A] with RandomAccessSeq.MutableProjection[A] with Projection0[A] { - override def elements : BufferIterator[Int,A] = new DefaultBufferIterator - override def projection : Projection = this - } - override def projection : Projection = new Projection } diff --git a/src/library/scala/collection/jcl/Buffer.scala b/src/library/scala/collection/jcl/Buffer.scala index d6dd45c501..a0a3348d0a 100644 --- a/src/library/scala/collection/jcl/Buffer.scala +++ b/src/library/scala/collection/jcl/Buffer.scala @@ -14,7 +14,7 @@ package scala.collection.jcl; * * @author Sean McDirmid */ -trait Buffer[A] extends Ranged[Int,A] with MutableSeq[A] with Collection[A] { +trait Buffer[A] extends RandomAccessSeq.Mutable[A] with Ranged[Int,A] with MutableSeq[A] with Collection[A] { final protected type SortedSelf = Buffer[A]; override def projection : Buffer.Projection[A] = new Buffer.Projection[A] { @@ -200,13 +200,26 @@ trait Buffer[A] extends Ranged[Int,A] with MutableSeq[A] with Collection[A] { } } } - def replace(startOffset : Int, length : Int, added : Iterable[A]) : Unit = { - + /* + protected class Map[B](f : A => B) extends super.Map[B](f) with Buffer.Projection[B] { + override def elements = Buffer.this.elements.map[B](f); + //override def apply(idx : Int) = f(MutableSeq.this.apply(idx)); + //override def size = length; } - + */ } object Buffer { - trait Projection[A] extends MutableSeq.Projection[A] with Collection.Projection[A] with Buffer[A] { - override def projection = this + trait Projection0[A] extends MutableSeq.Projection[A] with RandomAccessSeq.Projection[A] { + override def projection : Projection0[A] = this + override def elements : SeqIterator[Int,A] = new DefaultSeqIterator + + protected class MapProjection[B](f : A => B) extends super.MapProjection[B](f) with Projection0[B] { + override def projection = this + } + override def map[B](f: A => B) : Projection0[B] = new MapProjection[B](f) + } + class Projection[A] extends Collection.Projection[A] with RandomAccessSeq.MutableProjection[A] with Projection0[A] with Buffer[A] { + override def elements : BufferIterator[Int,A] = new DefaultBufferIterator + override def projection : Buffer.Projection[A] = this } } diff --git a/src/library/scala/collection/jcl/BufferIterator.scala b/src/library/scala/collection/jcl/BufferIterator.scala index 3faeb0b354..bb7b79d099 100644 --- a/src/library/scala/collection/jcl/BufferIterator.scala +++ b/src/library/scala/collection/jcl/BufferIterator.scala @@ -28,5 +28,4 @@ trait BufferIterator[K,A] extends SeqIterator[K,A] { * If previous was last called, "a" is inserted before the element returned. */ def add(a: A): Unit; - } diff --git a/src/library/scala/collection/jcl/MutableIterable.scala b/src/library/scala/collection/jcl/MutableIterable.scala index 5683e6bd3e..0fed9954e5 100644 --- a/src/library/scala/collection/jcl/MutableIterable.scala +++ b/src/library/scala/collection/jcl/MutableIterable.scala @@ -42,7 +42,7 @@ trait MutableIterable[A] extends scala.Collection[A] { def -(t : A) : this.type = { remove(t); this; } /** retain only elements in the collection that predicate p is true for. */ - def retain(p : A => Boolean) : Unit = elements.retain(p); + def retainOnly(p : A => Boolean) : Unit = elements.retain(p); /** retain only elements that are also in that. */ def retainAll(that : Iterable[A]) : Boolean = elements.retain(s => that.exists(t => t == s)); diff --git a/src/library/scala/collection/jcl/Set.scala b/src/library/scala/collection/jcl/Set.scala index 604e647f52..85c5b11148 100644 --- a/src/library/scala/collection/jcl/Set.scala +++ b/src/library/scala/collection/jcl/Set.scala @@ -24,7 +24,7 @@ trait Set[A] extends scala.collection.mutable.Set[A] with Collection[A] { override def --(i: Iterable[A]) : this.type = super[Collection].--(i) override def +(t: A) : this.type = super[Collection].+(t) override def -(t: A) : this.type = super[Collection].-(t) - override def retain(f: A => Boolean) = super[Collection].retain(f) + override final def retain(f: A => Boolean) = retainOnly(f) override def isEmpty = super[Collection].isEmpty override def clear() = super.clear() override def subsetOf(set : scala.collection.Set[A]) = set match { @@ -46,8 +46,8 @@ trait Set[A] extends scala.collection.mutable.Set[A] with Collection[A] { } class Filter(pp : A => Boolean) extends super.Filter with Set.Projection[A] { override def p(a : A) = pp(a) - override def retain(p0 : A => Boolean): Unit = - Set.this.retain(e => !p(e) || p0(e)) + override def retainOnly(p0 : A => Boolean): Unit = + Set.this.retainOnly(e => !p(e) || p0(e)) override def add(a : A) = { if (!p(a)) throw new IllegalArgumentException else Set.this.add(a) diff --git a/src/library/scala/collection/mutable/Map.scala b/src/library/scala/collection/mutable/Map.scala index 1f065cb6eb..0b5504a5e8 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -202,6 +202,7 @@ trait Map[A, B] extends AnyRef * p returns true. * * @param p The test predicate + * @deprecated cannot be type inferred because if retain in Iterable. */ def retain(p: (A, B) => Boolean): Unit = toList foreach { case (key, value) => if (!p(key, value)) -=(key) diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 73e9bfa749..f631a2688a 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -28,7 +28,7 @@ object ScalaRunTime { val DoubleTag = ".Double" val BooleanTag = ".Boolean" - def isArray(x: AnyRef): Boolean = x != null && x.getClass.isArray + def isArray(x: AnyRef): Boolean = (x != null && x.getClass.isArray) || (x != null && x.isInstanceOf[BoxedArray]) def isValueTag(tag: String) = tag.charAt(0) == '.' def isValueClass(clazz: Class) = clazz.isPrimitive() diff --git a/test/files/run/array_casts.check b/test/files/run/array_casts.check new file mode 100644 index 0000000000..f7d3e5036c --- /dev/null +++ b/test/files/run/array_casts.check @@ -0,0 +1,16 @@ +is object - true +is seq - true +is collection - true +is random-access-seq - true +is random-access-seq-mutable - true +not string - true +not list - true +class [I +Array(10) +Array(10) +Array(10) +Array(10) +Good, arrays are not lists +Good, arrays are not rich strings +is-seq array true +class [I diff --git a/test/files/run/array_casts.scala b/test/files/run/array_casts.scala new file mode 100644 index 0000000000..9d298bbc2b --- /dev/null +++ b/test/files/run/array_casts.scala @@ -0,0 +1,42 @@ +object Test { + val a = Array(10) + def main(args : Array[String]) : Unit = { + val a = this.a : AnyRef + Console.println("is object - " + a.isInstanceOf[Object]) + Console.println("is seq - " + a.isInstanceOf[Seq[_]]) + Console.println("is collection - " + a.isInstanceOf[Collection[_]]) + Console.println("is random-access-seq - " + a.isInstanceOf[RandomAccessSeq[_]]) + Console.println("is random-access-seq-mutable - " + a.isInstanceOf[RandomAccessSeq.Mutable[_]]) + Console.println("not string - " + !a.isInstanceOf[String]) + Console.println("not list - " + !a.isInstanceOf[List[_]]) + try { + Console.println(a.asInstanceOf[Object].getClass) + } catch { case ex : ClassCastException => Console.println("Bad, arrays should be objects") } + try { + Console.println(a.asInstanceOf[Seq[_]]) + } catch { case ex : ClassCastException => Console.println("Bad, arrays should be seqs") } + try { + Console.println(a.asInstanceOf[Collection[_]]) + } catch { case ex : ClassCastException => Console.println("Bad, arrays should be collections") } + try { + Console.println(a.asInstanceOf[RandomAccessSeq[_]]) + } catch { case ex : ClassCastException => Console.println("Bad, arrays should be random access seqs") } + try { + Console.println(a.asInstanceOf[RandomAccessSeq.Mutable[_]]) + } catch { case ex : ClassCastException => Console.println("Bad, arrays should be mutable random access seqs") } + try { + Console.println("not expected: " + a.asInstanceOf[List[_]]) + } catch { case ex : ClassCastException => Console.println("Good, arrays are not lists") } + try { + Console.println("not expected: " + a.asInstanceOf[runtime.RichString]) + throw new Error("not expected") + } catch { case ex : ClassCastException => Console.println("Good, arrays are not rich strings") } + // check that arrays as seqs are still dynamically typed as arrays + val s = this.a : Seq[Int] + Console.println("is-seq array " + s.isInstanceOf[Array[Char]]) + try { + Console.println(s.asInstanceOf[Array[Int]].getClass) + } catch { case ex : ClassCastException => Console.println("Bad, arrays as seqs should still be arrays of int") } + () + } +} -- cgit v1.2.3