diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-01-29 15:59:06 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-02-10 08:46:13 +0100 |
commit | 9f142b114be1261f55ea82b9cd1f9d9f91b3cad6 (patch) | |
tree | 4c966792f9f2c5a8466c4ca3510a59ca32929783 /test/files/neg | |
parent | 08e51dfec50842253afb87cc5ae3c7400dc18ced (diff) | |
download | scala-9f142b114be1261f55ea82b9cd1f9d9f91b3cad6.tar.gz scala-9f142b114be1261f55ea82b9cd1f9d9f91b3cad6.tar.bz2 scala-9f142b114be1261f55ea82b9cd1f9d9f91b3cad6.zip |
SI-6260 Avoid double-def error with lambdas over value classes
Post-erasure of value classs in method signatures to the underlying
type wreaks havoc when the erased signature overlaps with the
generic signature from an overriden method. There just isn't room
for both. But we *really* need both; callers to the interface method
will be passing boxed values that the bridge needs to unbox and
pass to the specific method that accepts unboxed values.
This most commonly turns up with value classes that erase to
Object that are used as the parameter or the return type of
an anonymous function.
This was thought to have been intractable, unless we chose
a different name for the unboxed, specific method in the
subclass. But that sounds like a big task that would require
call-site rewriting, ala specialization.
But there is an important special case in which we don't need
to rewrite call sites. If the class defining the method is
anonymous, there is actually no need for the unboxed method;
it will *only* ever be called via the generic method.
I came to this realisation when looking at how Java 8 lambdas
are handled. I was expecting bridge methods, but found none.
The lambda body is placed directly in a method exactly matching
the generic signature.
This commit detects the clash between bridge and target,
and recovers for anonymous classes by mangling the name
of the target method's symbol. This is used as the bytecode
name. The generic bridge forward to that, as before, with
the requisite box/unbox operations.
Diffstat (limited to 'test/files/neg')
-rw-r--r-- | test/files/neg/delambdafy_t6260_method.check | 13 | ||||
-rw-r--r-- | test/files/neg/delambdafy_t6260_method.flags | 1 | ||||
-rw-r--r-- | test/files/neg/delambdafy_t6260_method.scala | 17 | ||||
-rw-r--r-- | test/files/neg/t6260-named.check | 13 | ||||
-rw-r--r-- | test/files/neg/t6260-named.scala | 15 | ||||
-rw-r--r-- | test/files/neg/t6260.check | 13 | ||||
-rw-r--r-- | test/files/neg/t6260.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t6260.scala | 17 | ||||
-rw-r--r-- | test/files/neg/t6260b.check | 7 | ||||
-rw-r--r-- | test/files/neg/t6260b.scala | 3 |
10 files changed, 28 insertions, 72 deletions
diff --git a/test/files/neg/delambdafy_t6260_method.check b/test/files/neg/delambdafy_t6260_method.check deleted file mode 100644 index f5cd6947d1..0000000000 --- a/test/files/neg/delambdafy_t6260_method.check +++ /dev/null @@ -1,13 +0,0 @@ -delambdafy_t6260_method.scala:3: error: bridge generated for member method apply: (bx: Object)Object in class map$extension1 -which overrides method apply: (v1: Object)Object in trait Function1 -clashes with definition of the member itself; -both have erased type (bx: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(this) - ^ -delambdafy_t6260_method.scala:8: error: bridge generated for member method apply: (bx: Object)Object in class map21 -which overrides method apply: (v1: Object)Object in trait Function1 -clashes with definition of the member itself; -both have erased type (bx: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(self) - ^ -two errors found diff --git a/test/files/neg/delambdafy_t6260_method.flags b/test/files/neg/delambdafy_t6260_method.flags deleted file mode 100644 index 48b438ddf8..0000000000 --- a/test/files/neg/delambdafy_t6260_method.flags +++ /dev/null @@ -1 +0,0 @@ --Ydelambdafy:method diff --git a/test/files/neg/delambdafy_t6260_method.scala b/test/files/neg/delambdafy_t6260_method.scala deleted file mode 100644 index 93b5448227..0000000000 --- a/test/files/neg/delambdafy_t6260_method.scala +++ /dev/null @@ -1,17 +0,0 @@ -class Box[X](val x: X) extends AnyVal { - def map[Y](f: X => Y): Box[Y] = - ((bx: Box[X]) => new Box(f(bx.x)))(this) -} - -object Test { - def map2[X, Y](self: Box[X], f: X => Y): Box[Y] = - ((bx: Box[X]) => new Box(f(bx.x)))(self) - - def main(args: Array[String]) { - val f = (x: Int) => x + 1 - val g = (x: String) => x + x - - map2(new Box(42), f) - new Box("abc") map g - } -} diff --git a/test/files/neg/t6260-named.check b/test/files/neg/t6260-named.check new file mode 100644 index 0000000000..ed6ab5e76f --- /dev/null +++ b/test/files/neg/t6260-named.check @@ -0,0 +1,13 @@ +t6260-named.scala:12: error: bridge generated for member method apply: (a: C[Any])C[Any] in object O +which overrides method apply: (v1: T1)R in trait Function1 +clashes with definition of the member itself; +both have erased type (v1: Object)Object + def apply(a: C[Any]) = a + ^ +t6260-named.scala:14: error: bridge generated for member method apply: (a: C[Any])C[Any] in class X +which overrides method apply: (a: A)A in trait T +clashes with definition of the member itself; +both have erased type (a: Object)Object + class X extends T[C[Any]] { def apply(a: C[Any]) = a } + ^ +two errors found diff --git a/test/files/neg/t6260-named.scala b/test/files/neg/t6260-named.scala new file mode 100644 index 0000000000..7ce13476eb --- /dev/null +++ b/test/files/neg/t6260-named.scala @@ -0,0 +1,15 @@ +class C[A](private val a: Any) extends AnyVal +trait T[A] { + def apply(a: A): A +} + +object Test { + (x: C[Any]) => {println(s"f($x)"); x} // okay + new T[C[Any]] { def apply(a: C[Any]) = a } // okay + + // we can't rename the specific apply methid to avoid the clash + object O extends Function1[C[Any], C[Any]] { + def apply(a: C[Any]) = a + } + class X extends T[C[Any]] { def apply(a: C[Any]) = a } +} diff --git a/test/files/neg/t6260.check b/test/files/neg/t6260.check deleted file mode 100644 index 60c4add143..0000000000 --- a/test/files/neg/t6260.check +++ /dev/null @@ -1,13 +0,0 @@ -t6260.scala:3: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in <$anon: Box[X] => Box[Y]> -which overrides method apply: (v1: T1)R in trait Function1 -clashes with definition of the member itself; -both have erased type (v1: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(this) - ^ -t6260.scala:8: error: bridge generated for member method apply: (bx: Box[X])Box[Y] in <$anon: Box[X] => Box[Y]> -which overrides method apply: (v1: T1)R in trait Function1 -clashes with definition of the member itself; -both have erased type (v1: Object)Object - ((bx: Box[X]) => new Box(f(bx.x)))(self) - ^ -two errors found diff --git a/test/files/neg/t6260.flags b/test/files/neg/t6260.flags deleted file mode 100644 index 2349d8294d..0000000000 --- a/test/files/neg/t6260.flags +++ /dev/null @@ -1 +0,0 @@ --Ydelambdafy:inline diff --git a/test/files/neg/t6260.scala b/test/files/neg/t6260.scala deleted file mode 100644 index 93b5448227..0000000000 --- a/test/files/neg/t6260.scala +++ /dev/null @@ -1,17 +0,0 @@ -class Box[X](val x: X) extends AnyVal { - def map[Y](f: X => Y): Box[Y] = - ((bx: Box[X]) => new Box(f(bx.x)))(this) -} - -object Test { - def map2[X, Y](self: Box[X], f: X => Y): Box[Y] = - ((bx: Box[X]) => new Box(f(bx.x)))(self) - - def main(args: Array[String]) { - val f = (x: Int) => x + 1 - val g = (x: String) => x + x - - map2(new Box(42), f) - new Box("abc") map g - } -} diff --git a/test/files/neg/t6260b.check b/test/files/neg/t6260b.check deleted file mode 100644 index 3a7e8947aa..0000000000 --- a/test/files/neg/t6260b.check +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 73e2e58f73..0000000000 --- a/test/files/neg/t6260b.scala +++ /dev/null @@ -1,3 +0,0 @@ - -class X(val value: Object) extends AnyVal { def or(alt: => X): X = this } -class Y { def f = new X("") or new X("") } |