diff --git a/project/ScalaOptionParser.scala b/project/ScalaOptionParser.scala index f2fd4d86d7c0..34e05e62451d 100644 --- a/project/ScalaOptionParser.scala +++ b/project/ScalaOptionParser.scala @@ -90,7 +90,7 @@ object ScalaOptionParser { "-Ypresentation-strict", "-Ypresentation-verbose", "-Yquasiquote-debug", "-Yrangepos", "-Yreify-copypaste", "-Yreify-debug", "-Yrepl-class-based", "-Yrepl-sync", "-Yshow-member-pos", "-Yshow-symkinds", "-Yshow-symowners", "-Yshow-syms", "-Yshow-trees", "-Yshow-trees-compact", "-Yshow-trees-stringified", "-Ytyper-debug", "-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-inaccessible", "-Ywarn-infer-any", "-Ywarn-nullary-override", "-Ywarn-nullary-unit", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-unused-import", "-Ywarn-value-discard", - "-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version") + "-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version", "-Yuse-trait-statics") private def stringSettingNames = List("-Xgenerate-phase-graph", "-Xmain-class", "-Xpluginsdir", "-Xshow-class", "-Xshow-object", "-Xsource-reader", "-Ydump-classes", "-Ygen-asmp", "-Ypresentation-log", "-Ypresentation-replay", "-Yrepl-outdir", "-d", "-dependencyfile", "-encoding", "-Xscript") private def pathSettingNames = List("-bootclasspath", "-classpath", "-extdirs", "-javabootclasspath", "-javaextdirs", "-sourcepath", "-toolcp") diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 5d152ef0e8e2..ea17088d4e55 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -1061,7 +1061,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { val receiverName = internalName(receiverClass) // super calls are only allowed to direct parents - if (style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) { + if (!settings.YuseTraitStatics.value && style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) { thisBType.info.get.inlineInfo.lateInterfaces += receiverName cnode.interfaces.add(receiverName) } @@ -1082,7 +1082,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case Virtual => if (needsInterfaceCall(receiverClass)) bc.invokeinterface(receiverName, jname, mdescr, pos) else bc.invokevirtual (receiverName, jname, mdescr, pos) - case Super => bc.invokespecial (receiverName, jname, mdescr, pos) + case Super => + if (receiverClass.isTraitOrInterface && settings.YuseTraitStatics.value) { + val staticDesc = MethodBType(typeToBType(method.owner.info) :: method.info.paramTypes.map(typeToBType), typeToBType(method.info.resultType)).descriptor + bc.invokestatic(receiverName, jname, staticDesc, pos) + } else bc.invokespecial (receiverName, jname, mdescr, pos) } bmType.returnType diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index f190c1f2de26..32dbe6b26d24 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -489,7 +489,27 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { case ValDef(mods, name, tpt, rhs) => () // fields are added in `genPlainClass()`, via `addClassFields()` - case dd : DefDef => genDefDef(dd) + case dd : DefDef => + if (dd.symbol.owner.isTrait && dd.rhs != EmptyTree && !dd.symbol.isPrivate) { + // Split concrete methods in traits (including mixin constructors) into a static method + // with an explicit this parameter, and a non-static forwarder method. + val staticDefDef = { + val staticSym = dd.symbol.cloneSymbol + staticSym.setFlag(Flags.STATIC) + val selfParamSym = staticSym.newSyntheticValueParam(dd.symbol.owner.info, nme.SELF).setInfo(dd.symbol.owner.info) + staticSym.modifyInfo { + case mt @ MethodType(params, res) => copyMethodType(mt, selfParamSym :: params, res) + } + val selfParam = ValDef(selfParamSym) + treeCopy.DefDef(dd, dd.mods, dd.name, dd.tparams, (selfParam :: dd.vparamss.head) :: Nil, dd.tpt, dd.rhs).setSymbol(staticSym) + } + val forwarderDefDef = { + val forwarderBody = Apply(global.gen.mkAttributedRef(staticDefDef.symbol), This(dd.symbol.owner).setType(dd.symbol.owner.info) :: dd.vparamss.head.map(p => global.gen.mkAttributedIdent(p.symbol))).setType(dd.symbol.info.resultType) + deriveDefDef(dd)(_ => global.atPos(dd.pos)(forwarderBody)) + } + genDefDef(staticDefDef) + genDefDef(forwarderDefDef) + } else genDefDef(dd) case Template(_, _, body) => body foreach gen @@ -554,7 +574,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { val isNative = methSymbol.hasAnnotation(definitions.NativeAttr) val isAbstractMethod = rhs == EmptyTree - val flags = GenBCode.mkFlags( + var flags = GenBCode.mkFlags( javaFlags(methSymbol), if (isAbstractMethod) asm.Opcodes.ACC_ABSTRACT else 0, if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0, diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 7b9801175955..1953ef495cb6 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -202,6 +202,7 @@ trait ScalaSettings extends AbsScalaSettings val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212) val YclasspathImpl = ChoiceSetting ("-YclasspathImpl", "implementation", "Choose classpath scanning method.", List(ClassPathRepresentationType.Recursive, ClassPathRepresentationType.Flat), ClassPathRepresentationType.Flat) val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.") + val YuseTraitStatics = BooleanSetting ("-Yuse-trait-statics", "Emit super calls to trait methods with invokestatic") val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly() val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")