diff options
author | Martin Odersky <odersky@gmail.com> | 2012-02-15 12:04:36 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2012-02-15 12:04:36 +0100 |
commit | cd6426a8c501eda2105196fc5a254d8f0dd77633 (patch) | |
tree | 19f5640aa4aacc3ea34c48ae4882f6170258b93c /src/compiler | |
parent | ea96b48d9274e90b64b66e51507460c004c01643 (diff) | |
download | scala-cd6426a8c501eda2105196fc5a254d8f0dd77633.tar.gz scala-cd6426a8c501eda2105196fc5a254d8f0dd77633.tar.bz2 scala-cd6426a8c501eda2105196fc5a254d8f0dd77633.zip |
Changed array erasure scheme to never unbox elements of inline classes.
Diffstat (limited to 'src/compiler')
5 files changed, 72 insertions, 72 deletions
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index bd6a77fb07..2cf171aad3 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -118,7 +118,7 @@ trait Erasure { mapOver(tp) } - private def applyInArray(tp: Type): Type = tp match { + def applyInArray(tp: Type): Type = tp match { case TypeRef(pre, sym, args) if (sym.isInlineClass) => eraseNormalClassRef(pre, sym) case _ => apply(tp) } @@ -153,32 +153,42 @@ trait Erasure { * parents |Ps|, but with duplicate references of Object removed. * - for all other types, the type itself (with any sub-components erased) */ - def erasure(sym: Symbol, tp: Type): Type = { - if (sym != NoSymbol && sym.enclClass.isJavaDefined) { - val res = javaErasure(tp) - if (verifyJavaErasure && sym.isMethod) { - val old = scalaErasure(tp) - if (!(res =:= old)) - log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res) - } - res - } else - scalaErasure(tp) - } + def erasure(sym: Symbol): ErasureMap = + if (sym == NoSymbol || !sym.enclClass.isJavaDefined) scalaErasure + else if (verifyJavaErasure && sym.isMethod) verifiedJavaErasure + else javaErasure /** This is used as the Scala erasure during the erasure phase itself * It differs from normal erasure in that value classes are erased to ErasedInlineTypes which * are then later converted to the underlying parameter type in phase posterasure. */ - def specialErasure(sym: Symbol, tp: Type): Type = + def specialErasure(sym: Symbol)(tp: Type): Type = if (sym != NoSymbol && sym.enclClass.isJavaDefined) - erasure(sym, tp) + erasure(sym)(tp) else if (sym.isTerm && sym.owner.isInlineClass) specialErasureAvoiding(sym.owner, tp) else if (sym.isValue && sym.owner.isMethodWithExtension) specialErasureAvoiding(sym.owner.owner, tp) else - specialErasure(tp) + specialScalaErasure(tp) + + def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = { + tpe match { + case PolyType(tparams, restpe) => + specialErasureAvoiding(clazz, restpe) + case ExistentialType(tparams, restpe) => + specialErasureAvoiding(clazz, restpe) + case mt @ MethodType(params, restpe) => + MethodType( + cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)), + if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) + else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe))))) + case TypeRef(pre, `clazz`, args) => + typeRef(pre, clazz, List()) + case _ => + specialScalaErasure(tpe) + } + } /** Scala's more precise erasure than java's is problematic as follows: * @@ -200,31 +210,34 @@ trait Erasure { intersectionDominator(parents) } + class JavaErasureMap extends ErasureMap { + /** In java, always take the first parent. + * An intersection such as `Object with Trait` erases to Object. + */ + def mergeParents(parents: List[Type]): Type = + if (parents.isEmpty) ObjectClass.tpe + else parents.head + } + object scalaErasure extends ScalaErasureMap /** This is used as the Scala erasure during the erasure phase itself * It differs from normal erasure in that value classes are erased to ErasedInlineTypes which * are then later converted to the underlying parameter type in phase posterasure. */ - object specialErasure extends ScalaErasureMap { + object specialScalaErasure extends ScalaErasureMap { override def eraseInlineClassRef(clazz: Symbol): Type = ErasedInlineType(clazz) } - def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = { - tpe match { - case PolyType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) - case ExistentialType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) - case mt @ MethodType(params, restpe) => - MethodType( - cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)), - if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) - else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe))))) - case TypeRef(pre, `clazz`, args) => - typeRef(pre, clazz, List()) - case _ => - specialErasure(tpe) + object javaErasure extends JavaErasureMap + + object verifiedJavaErasure extends JavaErasureMap { + override def apply(tp: Type): Type = { + val res = javaErasure(tp) + val old = scalaErasure(tp) + if (!(res =:= old)) + log("Identified divergence between java/scala erasure:\n scala: " + old + "\n java: " + res) + res } } @@ -263,18 +276,9 @@ trait Erasure { } } - object javaErasure extends ErasureMap { - /** In java, always take the first parent. - * An intersection such as `Object with Trait` erases to Object. - */ - def mergeParents(parents: List[Type]): Type = - if (parents.isEmpty) ObjectClass.tpe - else parents.head - } - /** Type reference after erasure */ def erasedTypeRef(sym: Symbol): Type = - typeRef(erasure(sym, sym.owner.tpe), sym, Nil) + typeRef(erasure(sym)(sym.owner.tpe), sym, Nil) /** The symbol's erased info. This is the type's erasure, except for the following symbols: * @@ -288,25 +292,25 @@ trait Erasure { if (sym == Object_asInstanceOf) sym.info else if (sym == Object_isInstanceOf || sym == ArrayClass) - PolyType(sym.info.typeParams, specialErasure(sym, sym.info.resultType)) + PolyType(sym.info.typeParams, specialErasure(sym)(sym.info.resultType)) else if (sym.isAbstractType) TypeBounds(WildcardType, WildcardType) else if (sym.isTerm && sym.owner == ArrayClass) { if (sym.isClassConstructor) tp match { case MethodType(params, TypeRef(pre, sym1, args)) => - MethodType(cloneSymbolsAndModify(params, specialErasure(sym, _)), - typeRef(specialErasure(sym, pre), sym1, args)) + MethodType(cloneSymbolsAndModify(params, specialErasure(sym)), + typeRef(specialErasure(sym)(pre), sym1, args)) } else if (sym.name == nme.apply) tp else if (sym.name == nme.update) (tp: @unchecked) match { case MethodType(List(index, tvar), restpe) => - MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym, index.tpe)), tvar), + MethodType(List(index.cloneSymbol.setInfo(specialErasure(sym)(index.tpe)), tvar), erasedTypeRef(UnitClass)) } - else specialErasure(sym, tp) + else specialErasure(sym)(tp) } else if ( sym.owner != NoSymbol && sym.owner.owner == ArrayClass && @@ -316,7 +320,7 @@ trait Erasure { // symbol here tp } else { - specialErasure(sym, tp) + specialErasure(sym)(tp) } } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index b5232fff09..cc38979487 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -154,7 +154,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (settings.Ygenjavap.isDefault) { if(settings.Ydumpclasses.isDefault) new ClassBytecodeWriter { } - else + else new ClassBytecodeWriter with DumpBytecodeWriter { } } else new ClassBytecodeWriter with JavapBytecodeWriter { } @@ -209,7 +209,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val BeanInfoSkipAttr = definitions.getRequiredClass("scala.beans.BeanInfoSkip") val BeanDisplayNameAttr = definitions.getRequiredClass("scala.beans.BeanDisplayName") val BeanDescriptionAttr = definitions.getRequiredClass("scala.beans.BeanDescription") - + final val ExcludedForwarderFlags = { import Flags._ ( CASE | SPECIALIZED | LIFTED | PROTECTED | STATIC | BridgeAndPrivateFlags ) @@ -702,7 +702,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if ((settings.check.value contains "genjvm")) { val normalizedTpe = atPhase(currentRun.erasurePhase)(erasure.prepareSigMap(memberTpe)) val bytecodeTpe = owner.thisType.memberInfo(sym) - if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym, normalizedTpe) =:= bytecodeTpe)) { + if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) { clasz.cunit.warning(sym.pos, """|compiler bug: created generic signature for %s in %s that does not conform to its erasure |signature: %s diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 531a475bc6..cab440ef52 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -11,7 +11,7 @@ import Flags._ import scala.collection.{ mutable, immutable } import collection.mutable.ListBuffer -abstract class AddInterfaces extends InfoTransform { +abstract class AddInterfaces extends InfoTransform { self: Erasure => import global._ // the global environment import definitions._ // standard classes and methods @@ -21,14 +21,6 @@ abstract class AddInterfaces extends InfoTransform { */ override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE - /** Type reference after erasure; defined in Erasure. - */ - def erasedTypeRef(sym: Symbol): Type - - /** Erasure calculation; defined in Erasure. - */ - def erasure(sym: Symbol, tpe: Type): Type - /** A lazily constructed map that associates every non-interface trait with * its implementation class. */ @@ -175,14 +167,14 @@ abstract class AddInterfaces extends InfoTransform { /** If `tp` refers to a non-interface trait, return a * reference to its implementation class. Otherwise return `tp`. */ - def mixinToImplClass(tp: Type): Type = erasure(sym, + def mixinToImplClass(tp: Type): Type = erasure(sym) { tp match { //@MATN: no normalize needed (comes after erasure) case TypeRef(pre, sym, _) if sym.needsImplClass => typeRef(pre, implClass(sym), Nil) case _ => tp } - ) + } def implType(tp: Type): Type = tp match { case ClassInfoType(parents, decls, _) => assert(phase == implClassPhase, tp) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 5e481f570d..306e00e38d 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -290,7 +290,7 @@ abstract class Erasure extends AddInterfaces ) ) } - else jsig(erasure(sym0, tp), existentiallyBound, toplevel, primitiveOK) + else jsig(erasure(sym0)(tp), existentiallyBound, toplevel, primitiveOK) case PolyType(tparams, restpe) => assert(tparams.nonEmpty) val poly = if (toplevel) polyParamSig(tparams) else "" @@ -310,7 +310,7 @@ abstract class Erasure extends AddInterfaces println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type") jsig(bounds.hi, existentiallyBound, toplevel, primitiveOK) case _ => - val etp = erasure(sym0, tp) + val etp = erasure(sym0)(tp) if (etp eq tp) throw new UnknownSig else jsig(etp) } @@ -793,7 +793,7 @@ abstract class Erasure extends AddInterfaces val other = opc.overridden //println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG if (atPhase(currentRun.explicitouterPhase)(!member.isDeferred)) { - val otpe = erasure(owner, other.tpe) + val otpe = erasure(owner)(other.tpe) val bridgeNeeded = atPhase(phase.next) ( !(other.tpe =:= member.tpe) && !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) && @@ -838,7 +838,7 @@ abstract class Erasure extends AddInterfaces IF (typeTest) THEN bridgingCall ELSE REF(NoneModule) } else bridgingCall }); - debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner, member.tpe) + member.locationString + " =\n " + bridgeDef); + debuglog("generating bridge from " + other + "(" + Flags.flagsToString(bridge.flags) + ")" + ":" + otpe + other.locationString + " to " + member + ":" + erasure(owner)(member.tpe) + member.locationString + " =\n " + bridgeDef); bridgeDef } } :: bridges @@ -910,7 +910,7 @@ abstract class Erasure extends AddInterfaces gen.mkMethodCall( qual1(), fun.symbol, - List(specialErasure(fun.symbol, arg.tpe)), + List(specialErasure(fun.symbol)(arg.tpe)), Nil ), isArrayTest(qual1()) @@ -943,7 +943,7 @@ abstract class Erasure extends AddInterfaces // need to do the cast in adaptMember treeCopy.Apply( tree, - SelectFromArray(qual, name, erasure(tree.symbol, qual.tpe)).copyAttrs(fn), + SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn), args) } case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) => @@ -1064,7 +1064,7 @@ abstract class Erasure extends AddInterfaces && ct.typeValue.typeSymbol != definitions.UnitClass => val erased = ct.typeValue match { case TypeRef(pre, clazz, args) if clazz.isInlineClass => scalaErasure.eraseNormalClassRef(pre, clazz) - case tpe => specialErasure(NoSymbol, tpe) + case tpe => specialScalaErasure(tpe) } treeCopy.Literal(tree, Constant(erased)) @@ -1084,10 +1084,13 @@ abstract class Erasure extends AddInterfaces val tree1 = preErase(tree) tree1 match { case EmptyTree | TypeTree() => - tree1 setType specialErasure(NoSymbol, tree1.tpe) + tree1 setType specialScalaErasure(tree1.tpe) + case ArrayValue(elemtpt, trees) => + treeCopy.ArrayValue( + tree1, elemtpt setType specialScalaErasure.applyInArray(elemtpt.tpe), trees map transform) setType null case DefDef(_, _, _, _, tpt, _) => val result = super.transform(tree1) setType null - tpt.tpe = specialErasure(tree1.symbol, tree1.symbol.tpe).resultType + tpt.tpe = specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType result case _ => super.transform(tree1) setType null diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 064a3dd229..91ea7c7cd9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -515,7 +515,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R !other.isDeferred && other.isJavaDefined && { // #3622: erasure operates on uncurried types -- // note on passing sym in both cases: only sym.isType is relevant for uncurry.transformInfo - def uncurryAndErase(tp: Type) = erasure.erasure(sym, uncurry.transformInfo(sym, tp)) + // !!! erasure.erasure(sym, uncurry.transformInfo(sym, tp)) gives erreneous of inaccessible type - check whether that's still the case! + def uncurryAndErase(tp: Type) = erasure.erasure(sym)(uncurry.transformInfo(sym, tp)) val tp1 = uncurryAndErase(clazz.thisType.memberType(sym)) val tp2 = uncurryAndErase(clazz.thisType.memberType(other)) atPhase(currentRun.erasurePhase.next)(tp1 matches tp2) |