summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-06-29 20:45:10 +0000
committerPaul Phillips <paulp@improving.org>2011-06-29 20:45:10 +0000
commit5e193cc89ab8f154ac67ae658be6fbeca34ca572 (patch)
tree88b206501aa975e3cc4451e36764d0282ea16dcf
parente87bab490fddafe67841a39c06e68f8dec9e0868 (diff)
downloadscala-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.scala40
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala63
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 =>