summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala21
-rw-r--r--src/compiler/scala/tools/nsc/transform/PostErasure.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Constants.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala21
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala4
-rw-r--r--test/files/neg/t6260b.check7
-rw-r--r--test/files/neg/t6260b.scala3
-rw-r--r--test/files/neg/t6260c.check7
-rw-r--r--test/files/neg/t6260c.scala4
-rw-r--r--test/files/neg/t6385.check7
-rw-r--r--test/files/pos/t6260a.scala15
-rw-r--r--test/files/run/t6260b.scala13
-rw-r--r--test/files/run/t6385.scala (renamed from test/files/neg/t6385.scala)4
-rw-r--r--test/pending/run/t5866b.scala17
14 files changed, 102 insertions, 33 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index e2902a74b8..f0d3db1296 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -545,8 +545,7 @@ abstract class Erasure extends AddInterfaces
ldef setType ldef.rhs.tpe
case _ =>
val tree1 = tree.tpe match {
- case ErasedValueType(tref) =>
- val clazz = tref.sym
+ case ErasedValueType(clazz, _) =>
New(clazz, cast(tree, underlyingOfValueClass(clazz)))
case _ =>
tree.tpe.typeSymbol match {
@@ -597,9 +596,7 @@ abstract class Erasure extends AddInterfaces
ldef setType ldef.rhs.tpe
case _ =>
val tree1 = pt match {
- case ErasedValueType(tref) =>
- val clazz = tref.sym
- lazy val underlying = underlyingOfValueClass(clazz)
+ case ErasedValueType(clazz, underlying) =>
val tree0 =
if (tree.tpe.typeSymbol == NullClass &&
isPrimitiveValueClass(underlying.typeSymbol)) {
@@ -697,13 +694,11 @@ abstract class Erasure extends AddInterfaces
case Apply(ta @ TypeApply(sel @ Select(qual, name), List(targ)), List())
if tree.symbol == Any_asInstanceOf =>
val qual1 = typedQualifier(qual, NOmode, ObjectTpe) // need to have an expected type, see #3037
-
+ // !!! Make pending/run/t5866b.scala work. The fix might be here and/or in unbox1.
if (isPrimitiveValueType(targ.tpe) || isErasedValueType(targ.tpe)) {
val noNullCheckNeeded = targ.tpe match {
- case ErasedValueType(tref) =>
- enteringPhase(currentRun.erasurePhase) {
- isPrimitiveValueClass(erasedValueClassArg(tref).typeSymbol)
- }
+ case ErasedValueType(_, underlying) =>
+ isPrimitiveValueClass(underlying.typeSymbol)
case _ =>
true
}
@@ -724,7 +719,7 @@ abstract class Erasure extends AddInterfaces
case Apply(TypeApply(sel @ Select(qual, name), List(targ)), List())
if tree.symbol == Any_isInstanceOf =>
targ.tpe match {
- case ErasedValueType(tref) => targ.setType(tref.sym.tpe)
+ case ErasedValueType(clazz, _) => targ.setType(clazz.tpe)
case _ =>
}
tree
@@ -787,11 +782,11 @@ abstract class Erasure extends AddInterfaces
(tree.attachments.get[TypeRefAttachment]: @unchecked) match {
case Some(itype) =>
val tref = itype.tpe
- val argPt = enteringPhase(currentRun.erasurePhase)(erasedValueClassArg(tref))
+ val argPt = enteringErasure(erasedValueClassArg(tref))
log(s"transforming inject $arg -> $tref/$argPt")
val result = typed(arg, mode, argPt)
log(s"transformed inject $arg -> $tref/$argPt = $result:${result.tpe}")
- return result setType ErasedValueType(tref)
+ return result setType ErasedValueType(tref.sym, result.tpe)
}
case _ =>
diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
index 96263f3c0c..cc78e27282 100644
--- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
@@ -22,7 +22,7 @@ trait PostErasure extends InfoTransform with TypingTransformers {
object elimErasedValueType extends TypeMap {
def apply(tp: Type) = tp match {
case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp)))
- case ErasedValueType(tref) => enteringErasure(erasure.erasedValueClassArg(tref))
+ case ErasedValueType(_, underlying) => underlying
case _ => mapOver(tp)
}
}
diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala
index 511b39b8c6..85d0efdcba 100644
--- a/src/reflect/scala/reflect/internal/Constants.scala
+++ b/src/reflect/scala/reflect/internal/Constants.scala
@@ -223,7 +223,15 @@ trait Constants extends api.Constants {
case ClazzTag =>
def show(tpe: Type) = "classOf[" + signature(tpe) + "]"
typeValue match {
- case ErasedValueType(orig) => show(orig)
+ case ErasedValueType(clazz, underlying) =>
+ // A note on tpe_* usage here:
+ //
+ // We've intentionally erased the type arguments to the value class so that different
+ // instantiations of a particular value class that erase to the same underlying type
+ // don't result in spurious bridges (e.g. run/t6385.scala). I don't think that matters;
+ // printing trees of `classOf[ValueClass[String]]` shows `classOf[ValueClass]` at phase
+ // erasure both before and after the use of `tpe_*` here.
+ show(clazz.tpe_*)
case _ => show(typeValue)
}
case CharTag => "'" + escapedChar(charValue) + "'"
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 59d1e13142..653030e602 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -3341,18 +3341,25 @@ trait Types
/** A temporary type representing the erasure of a user-defined value type.
* Created during phase erasure, eliminated again in posterasure.
*
- * @param original The underlying type before erasure
+ * SI-6385 Erasure's creation of bridges considers method signatures `exitingErasure`,
+ * which contain `ErasedValueType`-s. In order to correctly consider the overriding
+ * and overriden signatures as equivalent in `run/t6385.scala`, it is critical that
+ * this type contains the erasure of the wrapped type, rather than the unerased type
+ * of the value class itself, as was originally done.
+ *
+ * @param valueClazz The value class symbol
+ * @param erasedUnderlying The erased type of the unboxed value
*/
- abstract case class ErasedValueType(original: TypeRef) extends UniqueType {
- override def safeToString = "ErasedValueType("+original+")"
+ abstract case class ErasedValueType(valueClazz: Symbol, erasedUnderlying: Type) extends UniqueType {
+ override def safeToString = s"ErasedValueType($valueClazz, $erasedUnderlying)"
}
- final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original)
+ final class UniqueErasedValueType(valueClazz: Symbol, erasedUnderlying: Type) extends ErasedValueType(valueClazz, erasedUnderlying)
object ErasedValueType {
- def apply(original: TypeRef): Type = {
- assert(original.sym ne NoSymbol, "ErasedValueType over NoSymbol")
- unique(new UniqueErasedValueType(original))
+ def apply(valueClazz: Symbol, erasedUnderlying: Type): Type = {
+ assert(valueClazz ne NoSymbol, "ErasedValueType over NoSymbol")
+ unique(new UniqueErasedValueType(valueClazz, erasedUnderlying))
}
}
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 185e2c3d1e..4aefc105e3 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -257,11 +257,11 @@ trait Erasure {
/** This is used as the Scala erasure during the erasure phase itself
* It differs from normal erasure in that value classes are erased to ErasedValueTypes which
- * are then later converted to the underlying parameter type in phase posterasure.
+ * are then later unwrapped to the underlying parameter type in phase posterasure.
*/
object specialScalaErasure extends ScalaErasureMap {
override def eraseDerivedValueClassRef(tref: TypeRef): Type =
- ErasedValueType(tref)
+ ErasedValueType(tref.sym, erasedValueClassArg(tref))
}
object javaErasure extends JavaErasureMap
diff --git a/test/files/neg/t6260b.check b/test/files/neg/t6260b.check
new file mode 100644
index 0000000000..3a7e8947aa
--- /dev/null
+++ b/test/files/neg/t6260b.check
@@ -0,0 +1,7 @@
+t6260b.scala:3: error: bridge generated for member method apply: ()X in <$anon: () => X>
+which overrides method apply: ()R in trait Function0
+clashes with definition of the member itself;
+both have erased type ()Object
+class Y { def f = new X("") or new X("") }
+ ^
+one error found
diff --git a/test/files/neg/t6260b.scala b/test/files/neg/t6260b.scala
new file mode 100644
index 0000000000..73e2e58f73
--- /dev/null
+++ b/test/files/neg/t6260b.scala
@@ -0,0 +1,3 @@
+
+class X(val value: Object) extends AnyVal { def or(alt: => X): X = this }
+class Y { def f = new X("") or new X("") }
diff --git a/test/files/neg/t6260c.check b/test/files/neg/t6260c.check
new file mode 100644
index 0000000000..cbbcfd1504
--- /dev/null
+++ b/test/files/neg/t6260c.check
@@ -0,0 +1,7 @@
+t6260c.scala:4: error: bridge generated for member method f: ()Option[A] in class Bar1
+which overrides method f: ()A in class Foo1
+clashes with definition of the member itself;
+both have erased type ()Object
+ class Bar1[A] extends Foo1[Option[A]] { def f(): Option[A] = ??? }
+ ^
+one error found
diff --git a/test/files/neg/t6260c.scala b/test/files/neg/t6260c.scala
new file mode 100644
index 0000000000..02bf152376
--- /dev/null
+++ b/test/files/neg/t6260c.scala
@@ -0,0 +1,4 @@
+final class Option[+A](val value: A) extends AnyVal
+
+abstract class Foo1[A] { def f(): A }
+ class Bar1[A] extends Foo1[Option[A]] { def f(): Option[A] = ??? }
diff --git a/test/files/neg/t6385.check b/test/files/neg/t6385.check
deleted file mode 100644
index 93e51e8927..0000000000
--- a/test/files/neg/t6385.check
+++ /dev/null
@@ -1,7 +0,0 @@
-t6385.scala:12: error: bridge generated for member method x: ()C[T] in class C
-which overrides method x: ()C[T] in trait AA
-clashes with definition of the member itself;
-both have erased type ()Object
- def x = this
- ^
-one error found
diff --git a/test/files/pos/t6260a.scala b/test/files/pos/t6260a.scala
new file mode 100644
index 0000000000..194294e981
--- /dev/null
+++ b/test/files/pos/t6260a.scala
@@ -0,0 +1,15 @@
+final class Option[+A](val value: A) extends AnyVal
+
+// Was: sandbox/test.scala:21: error: bridge generated for member method f: ()Option[A] in class Bar
+// which overrides method f: ()Option[A] in class Foo"
+abstract class Foo[A] { def f(): Option[A] }
+ class Bar[A] extends Foo[A] { def f(): Option[A] = ??? }
+
+// User reported this as erroneous but I couldn't reproduce with 2.10.{0,1,2,3}
+// https://issues.scala-lang.org/browse/SI-6260?focusedCommentId=64764&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-64764
+// I suspect he whittled down the example too far.
+class Wrapper(val value: Int) extends AnyVal
+abstract class Test { def check(the: Wrapper): Boolean }
+object T {
+ new Test { def check(the: Wrapper) = true }
+}
diff --git a/test/files/run/t6260b.scala b/test/files/run/t6260b.scala
new file mode 100644
index 0000000000..dd2cf4bc4e
--- /dev/null
+++ b/test/files/run/t6260b.scala
@@ -0,0 +1,13 @@
+class C[A](val a: A) extends AnyVal
+
+class DD {
+ def foo(c: C[String]) = ()
+ def bar[A <: String](c: C[A]) = ()
+ def baz[A](c: C[A]) = ()
+}
+
+object Test extends App {
+ classOf[DD].getMethod("foo", classOf[String])
+ classOf[DD].getMethod("bar", classOf[String])
+ classOf[DD].getMethod("baz", classOf[Object])
+}
diff --git a/test/files/neg/t6385.scala b/test/files/run/t6385.scala
index cec58eec9e..24fc3cd768 100644
--- a/test/files/neg/t6385.scala
+++ b/test/files/run/t6385.scala
@@ -1,8 +1,8 @@
-object N {
+object Test {
def main(args: Array[String]) {
val y: AA[Int] = C(2)
val c: Int = y.x.y
- println(c)
+ assert(c == 2)
}
}
trait AA[T] extends Any {
diff --git a/test/pending/run/t5866b.scala b/test/pending/run/t5866b.scala
new file mode 100644
index 0000000000..44d8b114b8
--- /dev/null
+++ b/test/pending/run/t5866b.scala
@@ -0,0 +1,17 @@
+class Foo(val d: Double) extends AnyVal {
+ override def toString = s"Foo($d)"
+}
+
+class Bar(val d: String) extends AnyVal {
+ override def toString = s"Foo($d)"
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val f: Foo = {val n: Any = null; n.asInstanceOf[Foo]}
+ println(f)
+
+ val b: Bar = {val n: Any = null; n.asInstanceOf[Bar]}
+ println(b)
+ }
+}