From c0ab376dd8c1ca891d68490083629780faecfcdf Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 12 Mar 2007 15:28:40 +0000 Subject: fixed bugs 910 and 995. --- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 6 +++ .../scala/tools/nsc/symtab/Definitions.scala | 1 + .../scala/tools/nsc/transform/Erasure.scala | 48 ++++++++++++++-------- src/library/scala/Seq.scala | 6 +-- src/library/scala/runtime/ScalaRunTime.scala | 2 +- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 2ff4b41266..15033d83e8 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -169,6 +169,12 @@ abstract class TreeGen { if (elems.isEmpty) Literal(()) else Apply(mkAttributedRef(definitions.TupleClass(elems.length).caseFactory), elems) + def mkAnd(tree1: Tree, tree2: Tree) = + Apply(Select(tree1, Boolean_and), List(tree2)) + + def mkOr(tree1: Tree, tree2: Tree) = + Apply(Select(tree1, Boolean_or), List(tree2)) + def mkCached(cvar: Symbol, expr: Tree): Tree = { val cvarRef = if (cvar.owner.isClass) Select(This(cvar.owner), cvar) else Ident(cvar) Block( diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index c8bea1c5fc..f3aedf5e9b 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -104,6 +104,7 @@ trait Definitions requires SymbolTable { var ScalaRunTimeModule: Symbol = _ def SeqFactory = getMember(ScalaRunTimeModule, nme.Seq); def checkDefinedMethod = getMember(ScalaRunTimeModule, "checkDefined") + def isArrayMethod = getMember(ScalaRunTimeModule, "isArray") var RepeatedParamClass: Symbol = _ var ByNameParamClass: Symbol = _ var UnsealedClass: Symbol = _ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 4809882041..d0150971a1 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -164,6 +164,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } + private def isSeqClass(sym: Symbol) = + (SeqClass isNonBottomSubClass sym) && (sym != ObjectClass) + // -------- boxing/unboxing -------------------------------------------------------- override def newTyper(context: Context) = new Eraser(context) @@ -279,7 +282,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } } - else if ((SeqClass isNonBottomSubClass pt.symbol) && pt.symbol != ObjectClass) + else if (isSeqClass(pt.symbol)) typed { atPos(tree.pos) { gen.evalOnce(tree, context.owner, context.unit) { x => @@ -403,15 +406,15 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List()) if ((tree.symbol == Any_asInstanceOf || tree.symbol == Any_asInstanceOfErased)) => val qual1 = typedQualifier(qual) - val targClass = targ.tpe.symbol val qualClass = qual1.tpe.symbol + val targClass = targ.tpe.symbol if (isNumericValueClass(qualClass) && isNumericValueClass(targClass)) // convert numeric type casts atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) else if (isValueType(targClass) || (targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass))) unbox(qual1, targ.tpe) - else if (targClass == ArrayClass && qualClass == ObjectClass) + else if (targClass == ArrayClass && qualClass == ObjectClass || isSeqClass(targClass)) cast(qual1, targ.tpe) else tree @@ -717,7 +720,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { EmptyTree case AliasTypeDef(_, _, _, _) => EmptyTree - case TypeApply(fun, args) if (fun.symbol.owner != AnyClass) => + case TypeApply(fun, args) if (fun.symbol.owner != AnyClass && + fun.symbol != Object_asInstanceOf && + fun.symbol != Object_isInstanceOf) => // leave all other type tests/type casts, remove all other type applications fun case Apply(fn, args) => @@ -743,6 +748,12 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { else if (fn.symbol == Any_isInstanceOf || fn.symbol == Any_isInstanceOfErased) fn match { case TypeApply(sel @ Select(qual, name), List(targ)) => + def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree = + Apply( + TypeApply( + Select(q(), Object_isInstanceOf) setPos sel.pos, + List(TypeTree(tp) setPos targ.pos)) setPos fn.pos, + List()) setPos tree.pos targ.tpe match { case SingleType(pre, sym) => val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq @@ -750,22 +761,23 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe))) } case RefinedType(parents, decls) if (parents.length >= 2) => - gen.evalOnce(qual, currentOwner, unit) { - q => - def mkIsInstanceOf(tp: Type) = - copy.Apply(tree, - copy.TypeApply(fn, - copy.Select(sel, q(), name), - List(TypeTree(tp))), - List()) - def mkAnd(tree1: Tree, tree2: Tree) = - atPos(tree1.pos) { - Apply(Select(tree1, Boolean_and), List(tree2)) - } - parents map mkIsInstanceOf reduceRight mkAnd + gen.evalOnce(qual, currentOwner, unit) { q => + atPos(tree.pos) { + parents map mkIsInstanceOf(q) reduceRight gen.mkAnd + } } case _ => - tree + if (isSeqClass(targ.tpe.symbol)) { + atPos(tree.pos) { + gen.evalOnce(qual, currentOwner, unit) { q => + gen.mkOr( + mkIsInstanceOf(q)(targ.tpe), + atPos(tree.pos) { + Apply(gen.mkAttributedRef(isArrayMethod), List(q())) + }) + } + } + } else tree } case _ => tree } diff --git a/src/library/scala/Seq.scala b/src/library/scala/Seq.scala index 19616c97c3..bdf2db2869 100644 --- a/src/library/scala/Seq.scala +++ b/src/library/scala/Seq.scala @@ -28,11 +28,7 @@ object Seq { * @param x the selector value * @return sequence wrapped in an option, if this is a Seq, otherwise none */ - def unapplySeq[A](x: Any): Option[Seq[A]] = x match { - case z: Seq[_] => Some(z.asInstanceOf[Seq[A]]) - case z: AnyRef if runtime.ScalaRunTime.isArray(z) => Some(runtime.ScalaRunTime.boxArray(z).asInstanceOf[Seq[A]]) - case _ => None - } + def unapplySeq[A](x: Seq[A]): Option[Seq[A]] = Some(x) /** Builds a singleton sequence. * diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index aec184f231..3bb0ca432e 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -29,7 +29,7 @@ object ScalaRunTime { val DoubleTag = ".Double" val BooleanTag = ".Boolean" - def isArray(x:AnyRef): Boolean = x.getClass.isArray + def isArray(x:AnyRef): Boolean = x != null && x.getClass.isArray def isValueTag(tag: String) = tag.charAt(0) == '.' def isValueClass(clazz: Class) = clazz.isPrimitive() -- cgit v1.2.3