From 4edbecfe9baaec89ced227f5bd6b92fb1f54e1ec Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 23 Sep 2009 15:01:27 +0000 Subject: Fixed #2381. --- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 4 +++ src/compiler/scala/tools/nsc/ast/Trees.scala | 20 +++++++++++-- src/compiler/scala/tools/nsc/symtab/Types.scala | 3 +- .../scala/tools/nsc/transform/Erasure.scala | 35 ++++++++++++---------- .../scala/tools/nsc/typechecker/Typers.scala | 8 ++++- 5 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index abf7026f3a..219f781605 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -278,6 +278,10 @@ abstract class TreeGen Apply(Select(mkAttributedRef(ScalaRunTimeModule), meth), args) } + def mkRuntimeCall(meth: Name, targs: List[Type], args: List[Tree]): Tree = { + Apply(TypeApply(Select(mkAttributedRef(ScalaRunTimeModule), meth), targs map TypeTree), args) + } + /** Make a synchronized block on 'monitor'. */ def mkSynchronized(monitor: Tree, body: Tree): Tree = Apply(Select(monitor, Object_synchronized), List(body)) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 945df94e91..20464f2468 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -821,7 +821,7 @@ trait Trees { def This(sym: Symbol): Tree = This(sym.name) setSymbol sym - /** Designator . */ + /** Designator . */ case class Select(qualifier: Tree, name: Name) extends RefTree { override def isTerm = name.isTermName @@ -886,7 +886,7 @@ trait Trees { case class SingletonTypeTree(ref: Tree) extends TypTree - /** Type selection # , eliminated by RefCheck */ + /** Type selection # , eliminated by RefCheck */ case class SelectFromTypeTree(qualifier: Tree, name: Name) extends TypTree with RefTree @@ -909,6 +909,10 @@ trait Trees { case class Parens(args: List[Tree]) extends Tree // only used during parsing + /** Array selection . only used during erasure */ + case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) + extends TermTree with RefTree + trait StubTree extends Tree { def underlying : AnyRef override def equalsStructure0(that: Tree)(f : (Tree,Tree) => Boolean): Boolean = this eq that @@ -1073,6 +1077,7 @@ trait Trees { def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree def TypeBoundsTree(tree: Tree, lo: Tree, hi: Tree): TypeBoundsTree def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]): ExistentialTypeTree + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type): SelectFromArray } class StrictTreeCopier extends TreeCopier { @@ -1164,6 +1169,8 @@ trait Trees { new TypeBoundsTree(lo, hi).copyAttrs(tree) def ExistentialTypeTree(tree: Tree, tpt: Tree, whereClauses: List[Tree]) = new ExistentialTypeTree(tpt, whereClauses).copyAttrs(tree) + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = + new SelectFromArray(qualifier, selector, erasure).copyAttrs(tree) } class LazyTreeCopier(treeCopy: TreeCopier) extends TreeCopier { @@ -1388,6 +1395,11 @@ trait Trees { if (tpt0 == tpt) && (whereClauses0 == whereClauses) => t case _ => treeCopy.ExistentialTypeTree(tree, tpt, whereClauses) } + def SelectFromArray(tree: Tree, qualifier: Tree, selector: Name, erasure: Type) = tree match { + case t @ SelectFromArray(qualifier0, selector0, _) + if (qualifier0 == qualifier) && (selector0 == selector) => t + case _ => treeCopy.SelectFromArray(tree, qualifier, selector, erasure) + } } abstract class Transformer { @@ -1510,6 +1522,8 @@ trait Trees { treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi)) case ExistentialTypeTree(tpt, whereClauses) => treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses)) + case SelectFromArray(qualifier, selector, erasure) => + treeCopy.SelectFromArray(tree, transform(qualifier), selector, erasure) case tree : StubTree => tree.symbol = NoSymbol tree.tpe = null @@ -1659,6 +1673,8 @@ trait Trees { traverse(lo); traverse(hi) case ExistentialTypeTree(tpt, whereClauses) => traverse(tpt); traverseTrees(whereClauses) + case SelectFromArray(qualifier, selector, erasure) => + traverse(qualifier) case Parens(ts) => traverseTrees(ts) case tree : StubTree => diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 39e6a7869c..b6deb501f0 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -2660,7 +2660,8 @@ A type's typeSymbol should never be inspected directly. private val emptySymCount = scala.collection.immutable.Map[Symbol, Int]() /** Make an existential variable. - * @param suffix A suffix to be appended to the freshly generated name + * [martin:] this should get moved to Symbols where the other symbols are created. + * @param name suffix to be appended to the freshly generated name * It's ususally "", except for type variables abstracting * over values, where it is ".type". * @param owner The owner of the variable diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index c9eb666bfb..e447921beb 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -116,15 +116,6 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. case st: SubType => apply(st.supertype) case TypeRef(pre, sym, args) => - def isGeneric(tp: Type): Boolean = tp match { - case TypeRef(pre, sym, args) => - sym.isAbstractType && !(sym.owner hasFlag JAVA) || - sym == ArrayClass && args.length == 1 && isGeneric(args.head) - case ExistentialType(tparams, restp) => - isGeneric(restp) - case _ => - false - } if (sym == ArrayClass) if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe else if (args.head.typeSymbol == NothingClass || args.head.typeSymbol == NullClass) arrayType(ObjectClass.tpe) @@ -406,7 +397,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. sym.tpe.resultType <:< bridge.tpe.resultType } -// -------- boxing/unboxing -------------------------------------------------------- +// -------- erasure on trees ------------------------------------------ override def newTyper(context: Context) = new Eraser(context) @@ -597,11 +588,15 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. assert(qual1.symbol.isStable, qual1.symbol); qual1 = Apply(qual1, List()) setPos qual1.pos setType qual1.tpe.resultType } else if (!(qual1.isInstanceOf[Super] || (qual1.tpe.typeSymbol isSubClass tree.symbol.owner))) { - // println("member cast "+tree.symbol+" "+tree.symbol.ownerChain+" "+qual1+" "+qual1.tpe) + assert(tree.symbol.owner != ArrayClass) qual1 = cast(qual1, tree.symbol.owner.tpe) } treeCopy.Select(tree, qual1, name) } + case SelectFromArray(qual, name, erasure) => + var qual1 = typedQualifier(qual) + if (!(qual1.tpe <:< erasure)) qual1 = cast(qual1, erasure) + Select(qual1, name) copyAttrs tree case _ => tree } @@ -638,6 +633,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. } def adaptBranch(branch: Tree): Tree = if (branch == EmptyTree) branch else adaptToType(branch, tree1.tpe); + tree1 match { case If(cond, thenp, elsep) => treeCopy.If(tree1, cond, adaptBranch(thenp), adaptBranch(elsep)) @@ -925,11 +921,18 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. fun.symbol != Object_isInstanceOf) => // leave all other type tests/type casts, remove all other type applications fun - case Apply(fn @ Select(qual, name), args) - if (fn.symbol.owner == ArrayClass && (unboundedGenericArrayLevel(qual.tpe.widen) == 1)) => - // convert calls to apply/update/length on generic arrays to - // calls of ScalaRunTime.array_xxx method calls - typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) } + case Apply(fn @ Select(qual, name), args) if (fn.symbol.owner == ArrayClass) => + if (unboundedGenericArrayLevel(qual.tpe.widen) == 1) + // convert calls to apply/update/length on generic arrays to + // calls of ScalaRunTime.array_xxx method calls + typedPos(tree.pos) { gen.mkRuntimeCall("array_"+name, qual :: args) } + else + // store exact array erasure in map to be retrieved later when we might + // need to do the cast in adaptMember + treeCopy.Apply( + tree, + SelectFromArray(qual, name, erasure(qual.tpe)).copyAttrs(fn), + args) case Apply(fn, args) => if (fn.symbol == Any_asInstanceOf) fn match { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 6a1bdc5ce1..d3f568ef1b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3570,9 +3570,15 @@ trait Typers { self: Analyzer => case Typed(expr, tpt) => if (treeInfo.isWildcardStarArg(tree)) { val expr0 = typed(expr, mode & stickyModes, WildcardType) + def subArrayType(pt: Type) = + if (isValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt) + else { + val tparam = makeFreshExistential("", context.owner, TypeBounds(NothingClass.tpe, pt)) + ExistentialType(List(tparam), arrayType(tparam.tpe)) + } val (expr1, baseClass) = if (expr0.tpe.typeSymbol == ArrayClass) - (adapt(expr0, mode & stickyModes, arrayType(pt)), ArrayClass) + (adapt(expr0, mode & stickyModes, subArrayType(pt)), ArrayClass) else (adapt(expr0, mode & stickyModes, seqType(pt)), SeqClass) expr1.tpe.baseType(baseClass) match { -- cgit v1.2.3