aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2017-04-11 18:59:48 +0200
committerGuillaume Martres <smarter@ubuntu.com>2017-04-11 19:26:35 +0200
commitd313143b4b4de1e6ac0a81582fc6164609a5eae1 (patch)
tree246835762d42dedd9d21764c3093b6eecbf14129
parent5a1bc13634ceea8fe1f120919293083045479cf9 (diff)
downloaddotty-d313143b4b4de1e6ac0a81582fc6164609a5eae1.tar.gz
dotty-d313143b4b4de1e6ac0a81582fc6164609a5eae1.tar.bz2
dotty-d313143b4b4de1e6ac0a81582fc6164609a5eae1.zip
SI-7455 Drop dummy param for synthetic access constructor
Adapted from scalac commit 050b4c951c838699c2fe30cbf01b63942c63a299 by Jason Zaugg: 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.
-rw-r--r--compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala18
1 files changed, 13 insertions, 5 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index e7306f956..bebc4ab2c 100644
--- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -194,13 +194,21 @@ class ClassfileParser(
val name = pool.getName(in.nextChar)
val isConstructor = name eq nme.CONSTRUCTOR
- /** Strip leading outer param from constructor.
- * Todo: Also strip trailing access tag for private inner constructors?
+ /** Strip leading outer param from constructor and trailing access tag for
+ * private inner constructors.
*/
- def stripOuterParamFromConstructor() = innerClasses.get(currentClassName) match {
+ def normalizeConstructorParams() = innerClasses.get(currentClassName) match {
case Some(entry) if !isStatic(entry.jflags) =>
val mt @ MethodTpe(paramNames, paramTypes, resultType) = denot.info
- denot.info = mt.derivedLambdaType(paramNames.tail, paramTypes.tail, resultType)
+ var normalizedParamNames = paramNames.tail
+ var normalizedParamTypes = paramTypes.tail
+ if ((jflags & JAVA_ACC_SYNTHETIC) != 0) {
+ // SI-7455 strip trailing dummy argument ("access constructor tag") from synthetic constructors which
+ // are added when an inner class needs to access a private constructor.
+ normalizedParamNames = paramNames.dropRight(1)
+ normalizedParamTypes = paramTypes.dropRight(1)
+ }
+ denot.info = mt.derivedLambdaType(normalizedParamNames, normalizedParamTypes, resultType)
case _ =>
}
@@ -216,7 +224,7 @@ class ClassfileParser(
denot.info = pool.getType(in.nextChar)
if (isEnum) denot.info = ConstantType(Constant(sym))
- if (isConstructor) stripOuterParamFromConstructor()
+ if (isConstructor) normalizeConstructorParams()
setPrivateWithin(denot, jflags)
denot.info = translateTempPoly(parseAttributes(sym, denot.info))
if (isConstructor) normalizeConstructorInfo()