summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala81
-rw-r--r--test/files/neg/primitive-sigs-1.check6
-rw-r--r--test/files/neg/primitive-sigs-1/A_1.scala9
-rw-r--r--test/files/neg/primitive-sigs-1/A_3.scala5
-rw-r--r--test/files/neg/primitive-sigs-1/J_2.java8
-rw-r--r--test/files/run/primitive-sigs-2.check3
-rw-r--r--test/files/run/primitive-sigs-2.scala20
7 files changed, 90 insertions, 42 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index a9a9180495..015481b97a 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -226,38 +226,39 @@ abstract class Erasure extends AddInterfaces
* type for constructors.
*/
def javaSig(sym0: Symbol, info: Type): Option[String] = atPhase(currentRun.erasurePhase) {
- def jsig(tp: Type, mustBox: Boolean) = {
- (boxedClass get tp.typeSymbol) match {
- case Some(boxed) if mustBox => jsig2(false, true, Nil, boxed.tpe)
- case _ => jsig2(false, mustBox, Nil, tp)
- }
- }
- def hiBounds(bounds: TypeBounds): List[Type] = bounds.hi.normalize match {
+ def jsig(tp: Type): String = jsig2(false, Nil, tp)
+
+ def boxedSig(tp: Type) = jsig(squashBoxed(tp))
+ def squashBoxed(tp: Type) =
+ if (boxedClass contains tp.typeSymbol) ObjectClass.tpe
+ else tp
+
+ 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, mustBox: Boolean, tparams: List[Symbol], tp0: Type): String = {
+ def jsig2(toplevel: Boolean, tparams: List[Symbol], tp0: Type): String = {
val tp = tp0.dealias
tp match {
case st: SubType =>
- jsig2(toplevel, mustBox, tparams, st.supertype)
+ jsig2(toplevel, tparams, st.supertype)
case ExistentialType(tparams, tpe) =>
- jsig2(toplevel, true, tparams, tpe)
+ jsig2(toplevel, tparams, tpe)
case TypeRef(pre, sym, args) =>
def argSig(tp: Type) =
if (tparams contains tp.typeSymbol) {
val bounds = tp.typeSymbol.info.bounds
if (AnyRefClass.tpe <:< bounds.hi) {
if (bounds.lo <:< NullClass.tpe) "*"
- else "-" + jsig(bounds.lo, true)
+ else "-" + boxedSig(bounds.lo)
}
- else "+" + jsig(bounds.hi, true)
+ else "+" + boxedSig(bounds.hi)
}
else if (tp.typeSymbol == UnitClass) {
- jsig(ObjectClass.tpe, true)
+ jsig(ObjectClass.tpe)
} else {
- jsig(tp, true)
+ boxedSig(tp)
}
def classSig = (
"L"+atPhase(currentRun.icodePhase)(sym.fullName + global.genJVM.moduleSuffix(sym)).replace('.', '/')
@@ -266,27 +267,27 @@ abstract class Erasure extends AddInterfaces
// If args isEmpty, Array is being used as a higher-kinded type
if (sym == ArrayClass && args.nonEmpty) {
- if (unboundedGenericArrayLevel(tp) == 1) jsig(ObjectClass.tpe, true)
- else ARRAY_TAG.toString+(args map (x => jsig(x, false))).mkString
+ if (unboundedGenericArrayLevel(tp) == 1) jsig(ObjectClass.tpe)
+ else ARRAY_TAG.toString+(args map jsig).mkString
}
else if (isTypeParameterInSig(sym))
TVAR_TAG.toString+sym.name+";"
else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass)
- jsig(ObjectClass.tpe, mustBox)
+ jsig(ObjectClass.tpe)
else if (sym == UnitClass)
- jsig(BoxedUnitClass.tpe, mustBox)
+ jsig(BoxedUnitClass.tpe)
else if (sym == NothingClass)
- jsig(RuntimeNothingClass.tpe, mustBox)
+ jsig(RuntimeNothingClass.tpe)
else if (sym == NullClass)
- jsig(RuntimeNullClass.tpe, mustBox)
+ jsig(RuntimeNullClass.tpe)
else if (isValueClass(sym))
- abbrvTag(sym).toString
+ jsig(ObjectClass.tpe)
else if (sym.isClass) {
val preRebound = pre.baseType(sym.owner) // #2585
dotCleanup(
(
if (needsJavaSig(preRebound)) {
- val s = jsig(preRebound, mustBox)
+ val s = jsig(preRebound)
if (s.charAt(0) == 'L') s.substring(0, s.length - 1) + classSigSuffix
else classSig
}
@@ -299,47 +300,43 @@ abstract class Erasure extends AddInterfaces
)
)
}
- else jsig(erasure(tp), mustBox)
+ else jsig(erasure(tp))
case PolyType(tparams, restpe) =>
assert(tparams.nonEmpty)
def boundSig(bounds: List[Type]) = {
val (isTrait, isClass) = bounds partition (_.typeSymbol.isTrait)
":" + (
- if (isClass.isEmpty) "" else jsig(isClass.head, true)
+ if (isClass.isEmpty) "" else boxedSig(isClass.head)
) + (
- isTrait map (x => ":" + jsig(x, true)) mkString
+ isTrait map (x => ":" + boxedSig(x)) mkString
)
}
def paramSig(tsym: Symbol) = tsym.name + boundSig(hiBounds(tsym.info.bounds))
val paramString = if (toplevel) tparams map paramSig mkString ("<", "", ">") else ""
- paramString + jsig(restpe, false)
+ paramString + jsig(restpe)
case MethodType(params, restpe) =>
- "("+(params map (_.tpe) map (x => jsig(x, false))).mkString+")"+
- (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe, false))
- case RefinedType(parents, decls) if (!parents.isEmpty) =>
- jsig(parents.head, mustBox)
+ "("+(params map (_.tpe) map jsig).mkString+")"+
+ (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
+ case RefinedType(parent :: _, decls) =>
+ jsig(parent)
case ClassInfoType(parents, _, _) =>
- (parents map (x => jsig(x, true))).mkString
+ (parents map jsig).mkString
case AnnotatedType(_, atp, _) =>
- jsig(atp, mustBox)
+ jsig(atp)
case BoundedWildcardType(bounds) =>
println("something's wrong: "+sym0+":"+sym0.tpe+" has a bounded wildcard type")
- jsig(bounds.hi, true)
+ jsig(bounds.hi)
case _ =>
val etp = erasure(tp)
if (etp eq tp) throw new UnknownSig
- else jsig(etp, mustBox)
+ else jsig(etp)
}
}
if (needsJavaSig(info)) {
- try {
- //println("Java sig of "+sym0+" is "+jsig2(true, List(), sym0.info))//DEBUG
- Some(jsig2(true, false, Nil, info))
- } catch {
- case ex: UnknownSig => None
- }
+ try Some(jsig2(true, Nil, info))
+ catch { case ex: UnknownSig => None }
}
else None
}
diff --git a/test/files/neg/primitive-sigs-1.check b/test/files/neg/primitive-sigs-1.check
new file mode 100644
index 0000000000..befb8219dd
--- /dev/null
+++ b/test/files/neg/primitive-sigs-1.check
@@ -0,0 +1,6 @@
+A_3.scala:3: error: type mismatch;
+ found : Bippy
+ required: AC[java.lang.Integer]
+ J_2.f(new Bippy())
+ ^
+one error found
diff --git a/test/files/neg/primitive-sigs-1/A_1.scala b/test/files/neg/primitive-sigs-1/A_1.scala
new file mode 100644
index 0000000000..0dd83b5d6a
--- /dev/null
+++ b/test/files/neg/primitive-sigs-1/A_1.scala
@@ -0,0 +1,9 @@
+// scala: the signature in the abstract class will use the
+// upper bound as return type, which for us will be Integer
+// since primitives can't appear in bounds.
+abstract class AC[T <: Int] {
+ def f(): T
+}
+class Bippy extends AC[Int] {
+ def f(): Int = 5
+} \ No newline at end of file
diff --git a/test/files/neg/primitive-sigs-1/A_3.scala b/test/files/neg/primitive-sigs-1/A_3.scala
new file mode 100644
index 0000000000..dec617a111
--- /dev/null
+++ b/test/files/neg/primitive-sigs-1/A_3.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ J_2.f(new Bippy())
+ }
+}
diff --git a/test/files/neg/primitive-sigs-1/J_2.java b/test/files/neg/primitive-sigs-1/J_2.java
new file mode 100644
index 0000000000..b416befb4d
--- /dev/null
+++ b/test/files/neg/primitive-sigs-1/J_2.java
@@ -0,0 +1,8 @@
+// java: often the java or scala compiler will save us from
+// the untruth in the signature, but not always.
+public class J_2 {
+ public static Integer f(AC<Integer> x) { return x.f(); }
+ public static void main(String[] args) {
+ f(new Bippy());
+ }
+}
diff --git a/test/files/run/primitive-sigs-2.check b/test/files/run/primitive-sigs-2.check
new file mode 100644
index 0000000000..4ecec9f199
--- /dev/null
+++ b/test/files/run/primitive-sigs-2.check
@@ -0,0 +1,3 @@
+T<java.lang.Object> interface scala.ScalaObject
+List(A, char, class java.lang.Object)
+a
diff --git a/test/files/run/primitive-sigs-2.scala b/test/files/run/primitive-sigs-2.scala
new file mode 100644
index 0000000000..a8876f7f60
--- /dev/null
+++ b/test/files/run/primitive-sigs-2.scala
@@ -0,0 +1,20 @@
+trait T[A] {
+ def f(): A
+}
+class C extends T[Char] {
+ def f(): Char = 'a'
+}
+
+object Test {
+ val c1: Class[_] = classOf[T[_]]
+ val c2: Class[_] = classOf[C]
+
+ val c1m = c1.getMethods.toList filter (_.getName == "f") map (_.getGenericReturnType.toString)
+ val c2m = c2.getMethods.toList filter (_.getName == "f") map (_.getGenericReturnType.toString)
+
+ def main(args: Array[String]): Unit = {
+ println(c2.getGenericInterfaces.map(_.toString).sorted mkString " ")
+ println(c1m ++ c2m sorted)
+ println(new C f)
+ }
+}