diff options
author | Paul Phillips <paulp@improving.org> | 2011-06-29 20:45:10 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2011-06-29 20:45:10 +0000 |
commit | 5e193cc89ab8f154ac67ae658be6fbeca34ca572 (patch) | |
tree | 88b206501aa975e3cc4451e36764d0282ea16dcf | |
parent | e87bab490fddafe67841a39c06e68f8dec9e0868 (diff) | |
download | scala-5e193cc89ab8f154ac67ae658be6fbeca34ca572.tar.gz scala-5e193cc89ab8f154ac67ae658be6fbeca34ca572.tar.bz2 scala-5e193cc89ab8f154ac67ae658be6fbeca34ca572.zip |
Added test that signatures conform to their era...
Added test that signatures conform to their erasures. Work in progress.
Review by extempore.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala | 40 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 63 |
2 files changed, 88 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index f10d6460bf..64572deb1c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -482,17 +482,35 @@ abstract class GenJVM extends SubComponent with GenJVMUtil { val memberTpe = atPhase(currentRun.erasurePhase)(owner.thisType.memberInfo(sym)) // println("addGenericSignature sym: " + sym.fullName + " : " + memberTpe + " sym.info: " + sym.info) // println("addGenericSignature: "+ (sym.ownerChain map (x => (x.name, x.isImplClass)))) - erasure.javaSig(sym, memberTpe) match { - case Some(sig) => - val index = jmember.getConstantPool().addUtf8(sig).toShort - if (settings.debug.value && settings.verbose.value) - atPhase(currentRun.erasurePhase) { - println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index) - } - val buf = ByteBuffer.allocate(2) - buf.putShort(index) - addAttribute(jmember, nme.SignatureATTR, buf) - case None => + erasure.javaSig(sym, memberTpe) foreach { sig => + /** Since we're using a sun internal class for signature validation, + * we have to allow for it not existing or otherwise malfunctioning: + * in which case we treat every signature as valid. Medium term we + * should certainly write independent signature validation. + */ + if (SigParser.isParserAvailable && isValidSignature(sym, sig)) { + val normalizedTpe = erasure.prepareSigMap(memberTpe) + val bytecodeTpe = owner.thisType.memberInfo(sym) + if (erasure.erasure(normalizedTpe) =:= bytecodeTpe) { + val index = jmember.getConstantPool.addUtf8(sig).toShort + if (opt.verboseDebug) + atPhase(currentRun.erasurePhase) { + println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index) + } + val buf = ByteBuffer.allocate(2) + buf putShort index + addAttribute(jmember, tpnme.SignatureATTR, buf) + } else clasz.cunit.warning(sym.pos, + """|compiler bug: created generic signature for %s in %s that does not conform to its erasure + |signature: %s + |erasure type: %s + |if this is reproducible, please report bug at http://lampsvn.epfl.ch/trac/scala + """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, bytecodeTpe)) + } else clasz.cunit.warning(sym.pos, + """|compiler bug: created invalid generic signature for %s in %s + |signature: %s + |if this is reproducible, please report bug at http://lampsvn.epfl.ch/trac/scala + """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig)) } } } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 5b46fec5fd..257e46914b 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -239,11 +239,66 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. // for debugging signatures: traces logic given system property private val traceSig = util.Tracer(sys.props contains "scalac.sigs.trace") + val prepareSigMap = new TypeMap { + def squashBoxed(tp: Type): Type = tp.normalize match { + case t @ RefinedType(parents, decls) => + val parents1 = parents mapConserve squashBoxed + if (parents1 eq parents) tp + else RefinedType(parents1, decls) + case t => + if (boxedClass contains t.typeSymbol) ObjectClass.tpe + else tp + } + def apply(tp: Type): Type = tp.normalize match { + case tp1 @ TypeBounds(lo, hi) => + val lo1 = squashBoxed(apply(lo)) + val hi1 = squashBoxed(apply(hi)) + if ((lo1 eq lo) && (hi1 eq hi)) tp1 + else TypeBounds(lo1, hi1) + case tp1 @ TypeRef(pre, sym, args) => + def argApply(tp: Type) = { + val tp1 = apply(tp) + if (tp1.typeSymbol == UnitClass) ObjectClass.tpe + else squashBoxed(tp1) + } + if (sym == ArrayClass && args.nonEmpty) + if (unboundedGenericArrayLevel(tp) == 1) ObjectClass.tpe + else mapOver(tp1) + else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass) + ObjectClass.tpe + else if (sym == UnitClass) + BoxedUnitClass.tpe + else if (sym == NothingClass) + RuntimeNothingClass.tpe + else if (sym == NullClass) + RuntimeNullClass.tpe + else { + val pre1 = apply(pre) + val args1 = args mapConserve argApply + if ((pre1 eq pre) && (args1 eq args)) tp1 + else TypeRef(pre1, sym, args1) + } + case tp1 @ MethodType(params, restpe) => + val params1 = mapOver(params) + val restpe1 = if (restpe.normalize.typeSymbol == UnitClass) UnitClass.tpe else apply(restpe) + if ((params1 eq params) && (restpe1 eq restpe)) tp1 + else MethodType(params1, restpe1) + case tp1 @ RefinedType(parents, decls) => + val parents1 = parents mapConserve apply + if (parents1 eq parents) tp1 + else RefinedType(parents1, decls) + case tp1: ClassInfoType => + tp1 + case tp1 => + mapOver(tp1) + } + } + /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ def javaSig(sym0: Symbol, info: Type): Option[String] = atPhase(currentRun.erasurePhase) { - def jsig(tp: Type): String = jsig2(false, Nil, tp) + def jsig(tp: Type): String = jsig2(toplevel = false, Nil, tp) def boxedSig(tp: Type) = (boxedClass get tp.typeSymbol) match { case Some(boxed) => jsig(boxed.tpe) @@ -251,10 +306,10 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer with ast. } def hiBounds(bounds: TypeBounds): List[Type] = bounds.hi.normalize match { case RefinedType(parents, _) => parents map normalize - case tp => List(tp) - } + case tp => tp :: Nil + }) map squashBoxed - def jsig2(toplevel: Boolean, tparams: List[Symbol], tp0: Type): String = traceSig("jsig2", toplevel, tparams, tp0) { + def jsig2(toplevel: Boolean, existentiallyBound: List[Symbol], tp0: Type): String = { val tp = tp0.dealias tp match { case st: SubType => |