summaryrefslogtreecommitdiff
path: root/test/files/run/t8710.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-07-11 11:05:59 +0200
committerJason Zaugg <jzaugg@gmail.com>2014-07-11 15:43:20 +0200
commitf36e7008937a1672c0e57dbf2eefe7a80e8988d7 (patch)
tree428de605917c244ff68a7b8c84f7a8c2293e0658 /test/files/run/t8710.scala
parent47c62158b98d6faa74c7466dd30c28ad421ae8ff (diff)
downloadscala-f36e7008937a1672c0e57dbf2eefe7a80e8988d7.tar.gz
scala-f36e7008937a1672c0e57dbf2eefe7a80e8988d7.tar.bz2
scala-f36e7008937a1672c0e57dbf2eefe7a80e8988d7.zip
SI-8710 Fix crasher for value classes + private + overloading
The link between methods owned by a value class and the corresponding extension method in the companion is governed in part by a naming convention that depends on how many eponymous decls exist. This is easiest to explain with an example: % cat sandbox/test.scala && \ qscalac -Xprint:extmethods sandbox/test.scala \ | egrep 'class|object|def (foo|bar)|}$' class C(val x: Any) extends AnyVal { def foo(a: Int) = "" def foo(a: String) = "" def bar(a: Byte) } final class C extends scala.AnyVal { def foo(a: Int): String = C.foo$extension0(C.this)(a); def foo(a: String): String = C.foo$extension1(C.this)(a); def bar(a: Byte): Unit = C.bar$extension(C.this)(a); } <synthetic> object C extends AnyRef { final def foo$extension0($this: C)(a: Int): String = ""; final def foo$extension1($this: C)(a: String): String = ""; final def bar$extension($this: C)(a: Byte): Unit = (<empty>.asInstanceOf[Unit]: Unit); } } } Notice how the extension method names for `foo` are suffixed with a counter. This logic is contained in `extensionNames`. However, in the enclosed test cases, when we call `extensionNames` in a late phase of the compiler, in particular during erasure when we rewire `new C(x).foo(args)` to `C.foo$extensionN(x)(args)`, we crash. Why? The private method in the value class has been name mangled by `ExplicitOuter`'s use of `makeNotPrivate`, and we no longer appear to have multiple eponymous methods in play. We could try to fix this by changing `extensionNames` to poke around through the scopes of the value class and its companion in a manner insensitive to expanded names. This might look something like: - info.decl(imeth.name) + newOverloadedSymbol(info.decls.filter(sym => unexpandedName(sym) == unexpandedName(imeth.name)) But in fact we never need to expand the name of a private method in an value class, nor its corresponding companion, as: - calls to private value class members end up as calls to public extension methods - extension methods already have a the `$extension[N]` suffix and need no further mangling. This commit: - Resets `PRIVATE` and `LOCAL` when deriving the extension method - Adds a special case to `ExplicitOuter` to imbue the special knowledge that a call to `SomeValueClass#somePrivateMethod` need not `makeNotPrivate`, as erasure will come along later and rewire that to a (public) extension method.
Diffstat (limited to 'test/files/run/t8710.scala')
-rw-r--r--test/files/run/t8710.scala17
1 files changed, 17 insertions, 0 deletions
diff --git a/test/files/run/t8710.scala b/test/files/run/t8710.scala
new file mode 100644
index 0000000000..15aab5b8a4
--- /dev/null
+++ b/test/files/run/t8710.scala
@@ -0,0 +1,17 @@
+class Bar(val x: Int) extends AnyVal {
+ def f: String = f(0)
+ private def f(x: Int): String = ""
+}
+
+class Baz(val x: Int) extends AnyVal {
+ def f: String = "123"
+ private def f(x: Int): String = ""
+}
+object Baz {
+ def x(b: Baz) = b.f(0)
+}
+
+object Test extends App {
+ new Bar(23).f
+ new Baz(23).f
+}