diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2017-04-11 18:59:48 +0200 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2017-04-11 19:26:35 +0200 |
commit | d313143b4b4de1e6ac0a81582fc6164609a5eae1 (patch) | |
tree | 246835762d42dedd9d21764c3093b6eecbf14129 /compiler/src/dotty/tools/dotc/core/classfile | |
parent | 5a1bc13634ceea8fe1f120919293083045479cf9 (diff) | |
download | dotty-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.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/classfile')
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala | 18 |
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() |