Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SI-7455 Drop dummy param for synthetic access constructor
Java synthesizes public constructors in private classes to allow access from inner classes. The signature of that synthetic constructor (known as a "access constructor") has a dummy parameter appended to avoid overloading clashes. javac chooses the type "Enclosing$1" for the dummy parameter (called the "access constructor tag") which is either an existing anonymous class or a synthesized class for this purpose. In OpenJDK, this transformation is performed in: langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java (Incidentally, scalac would just emits a byte-code public constructor in this situation, rather than a private constructor / access constructor pair.) Scala parses the signature of the access contructor, and drops the $outer parameter, but retains the dummy parameter. This causes havoc when it tries to parse the bytecode for that anonymous class; the class file parser doesn't have the enclosing type parameters of Vector in scope and crash ensues. In any case, we shouldn't allow user code to see that constructor; it should only be called from within its own compilation unit. This commit drops the dummy parameter from access constructor signatures in class file parsing.
- Loading branch information
Showing
4 changed files
with
76 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,4 @@ | |||
private[package <empty>] def <init>(x$1: String): Outer[E] | |||
private[package <empty>] def <init>(): Outer$PrivateInner | |||
private[package <empty>] def <init>(): Outer$PrivateStaticInner | |||
private[package <empty>] def <init>(x$2: String): Outer$PublicInner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,31 @@ | |||
public class Outer<E> { | |||
public void elements() { | |||
new C<E>() { | |||
}; | |||
} | |||
|
|||
private Outer(String a) {} | |||
|
|||
static class SubSelf extends Outer<String> { | |||
public SubSelf() { super(""); } | |||
} | |||
|
|||
private class PrivateInner { | |||
} | |||
class SubPrivateInner extends PrivateInner { | |||
} | |||
|
|||
private class PublicInner { | |||
private PublicInner(String a) {} | |||
} | |||
class SubPublicInner extends PublicInner { | |||
public SubPublicInner() { super(""); } | |||
} | |||
|
|||
private static class PrivateStaticInner { | |||
} | |||
public static class SubPrivateStaticInner extends PrivateStaticInner { | |||
} | |||
} | |||
|
|||
class C<E> {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,30 @@ | |||
import scala.tools.partest._ | |||
|
|||
// javac adds dummy parameters of type Outer$1 to synthetic access constructors | |||
// This test shows that we strip them from the signatures. If we don't, we trigger | |||
// parsing of Outer$1 which can fail if it references type parameters of the Outer. | |||
// | |||
// OLD OUTPUT: | |||
// private[package <empty>] def <init>(x$2: Outer$1): Outer$PrivateInner | |||
// error: error while loading Outer$1, class file 't7455-run.obj/Outer$1.class' is broken | |||
// (class java.util.NoSuchElementException/key not found: E) | |||
// ... | |||
object Test extends DirectTest { | |||
override def code = "" | |||
|
|||
def show { | |||
val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator") | |||
val compiler = newCompiler("-cp", classpath, "-d", testOutput.path) | |||
import compiler._, definitions._ | |||
new compiler.Run | |||
|
|||
for { | |||
name <- Seq("Outer", "Outer$PrivateInner", "Outer$PrivateStaticInner", "Outer$PublicInner") | |||
clazz = compiler.rootMirror.staticClass(name) | |||
constr <- clazz.info.member(nme.CONSTRUCTOR).alternatives | |||
} { | |||
println(constr.defString) | |||
fullyInitializeSymbol(constr) | |||
} | |||
} | |||
} |