diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-07-11 11:05:59 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-07-11 15:43:20 +0200 |
commit | f36e7008937a1672c0e57dbf2eefe7a80e8988d7 (patch) | |
tree | 428de605917c244ff68a7b8c84f7a8c2293e0658 /test/files/run | |
parent | 47c62158b98d6faa74c7466dd30c28ad421ae8ff (diff) | |
download | scala-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')
-rw-r--r-- | test/files/run/t8710.scala | 17 |
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 +} |