summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/transform/Erasure.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala9
-rw-r--r--test/files/neg/t4098.check13
-rw-r--r--test/files/neg/t4098.scala22
-rw-r--r--test/files/pos/t2435.scala27
-rw-r--r--test/files/pos/t5654.scala13
6 files changed, 92 insertions, 1 deletions
diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala
index 1b323f839b..5beec70d62 100644
--- a/src/compiler/scala/reflect/internal/transform/Erasure.scala
+++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala
@@ -17,7 +17,14 @@ trait Erasure {
* with primitive as well as class types)?.
*/
private def genericCore(tp: Type): Type = tp.normalize match {
- case TypeRef(_, sym, _) if sym.isAbstractType && !sym.owner.isJavaDefined =>
+ /* A Java Array<T> is erased to Array[Object] (T can only be a reference type), where as a Scala Array[T] is
+ * erased to Object. However, there is only symbol for the Array class. So to make the distinction between
+ * a Java and a Scala array, we check if the owner of T comes from a Java class.
+ * This however caused issue SI-5654. The additional test for EXSITENTIAL fixes it, see the ticket comments.
+ * In short, members of an existential type (e.g. `T` in `forSome { type T }`) can have pretty arbitrary
+ * owners (e.g. when computing lubs, <root> is used). All packageClass symbols have `isJavaDefined == true`.
+ */
+ case TypeRef(_, sym, _) if sym.isAbstractType && (!sym.owner.isJavaDefined || sym.hasFlag(Flags.EXISTENTIAL)) =>
tp
case ExistentialType(tparams, restp) =>
genericCore(restp)
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 6bed0b1228..b878ce3a53 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1279,6 +1279,15 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
}
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
+ case t if treeInfo.isSelfConstrCall(t) =>
+ assert(index == 0, index)
+ val t = transform(tree)
+ if (currentLevel.maxindex > 0) {
+ // An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717
+ debuglog("refsym = " + currentLevel.refsym)
+ unit.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation")
+ }
+ List(t)
case ModuleDef(_, _, _) => eliminateModuleDefs(tree)
case ValDef(_, _, _, _) =>
val tree1 @ ValDef(_, _, _, rhs) = transform(tree) // important to do before forward reference check
diff --git a/test/files/neg/t4098.check b/test/files/neg/t4098.check
new file mode 100644
index 0000000000..7d69cf151c
--- /dev/null
+++ b/test/files/neg/t4098.check
@@ -0,0 +1,13 @@
+t4098.scala:3: error: forward reference not allowed from self constructor invocation
+ this(b)
+ ^
+t4098.scala:8: error: forward reference not allowed from self constructor invocation
+ this(b)
+ ^
+t4098.scala:13: error: forward reference not allowed from self constructor invocation
+ this(b)
+ ^
+t4098.scala:18: error: forward reference not allowed from self constructor invocation
+ this(b)
+ ^
+four errors found
diff --git a/test/files/neg/t4098.scala b/test/files/neg/t4098.scala
new file mode 100644
index 0000000000..744d6191b5
--- /dev/null
+++ b/test/files/neg/t4098.scala
@@ -0,0 +1,22 @@
+class A(a: Any) {
+ def this() = {
+ this(b)
+ def b = new {}
+ }
+
+ def this(x: Int) = {
+ this(b)
+ lazy val b = new {}
+ }
+
+ def this(x: Int, y: Int) = {
+ this(b)
+ val b = new {}
+ }
+
+ def this(x: Int, y: Int, z: Int) = {
+ this(b)
+ println(".")
+ def b = new {}
+ }
+}
diff --git a/test/files/pos/t2435.scala b/test/files/pos/t2435.scala
new file mode 100644
index 0000000000..2db931b99f
--- /dev/null
+++ b/test/files/pos/t2435.scala
@@ -0,0 +1,27 @@
+object Bug {
+ abstract class FChain {
+ type T
+
+ def chain(constant:String) =
+ new FConstant[this.type](constant, this) //removing [this.type], everything compiles
+ }
+
+ case class FConstant[E <: FChain](constant:String, tail:E) extends FChain {
+ type T = tail.T
+ }
+
+ object FNil extends FChain {
+ type T = Unit
+ }
+
+}
+
+object Test {
+ import Bug._
+ println("Compiles:")
+ val a1 = FNil.chain("a").chain("a")
+ val a2 = a1.chain("a")
+
+ println("\nDoesn't compile:")
+ val a = FNil.chain("a").chain("a").chain("a")
+}
diff --git a/test/files/pos/t5654.scala b/test/files/pos/t5654.scala
new file mode 100644
index 0000000000..1f8d05bfed
--- /dev/null
+++ b/test/files/pos/t5654.scala
@@ -0,0 +1,13 @@
+class T(val a: Array[_])
+
+class U {
+ val a = Array(Array(1, 2), Array("a","b"))
+}
+
+class T1 { val a: Array[_] = Array(1) }
+
+case class Bomb(a: Array[_])
+case class Bomb2(a: Array[T] forSome { type T })
+class Okay1(a: Array[_])
+case class Okay2(s: Seq[_])
+