Skip to content

Commit 2e4d159

Browse files
committed
Support Scala 2.12 mixins
Adapt to either 2.11 or 2.12 scheme.
1 parent e5362ad commit 2e4d159

File tree

5 files changed

+70
-26
lines changed

5 files changed

+70
-26
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Compiler {
7575
new InterceptedMethods, // Special handling of `==`, `|=`, `getClass` methods
7676
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
7777
new ElimByName, // Expand by-name parameter references
78-
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
78+
new AugmentScala2Traits, // Expand traits defined in Scala 2.x to simulate old-style rewritings
7979
new ResolveSuper, // Implement super accessors and add forwarders to trait methods
8080
new Simplify, // Perform local optimizations, simplified versions of what linker does.
8181
new PrimitiveForwarders, // Add forwarders to trait methods that have a mismatch between generic and primitives
@@ -87,15 +87,15 @@ class Compiler {
8787
new Mixin, // Expand trait fields and trait initializers
8888
new LazyVals, // Expand lazy vals
8989
new Memoize, // Add private fields to getters and setters
90-
new LinkScala2ImplClasses, // Forward calls to the implementation classes of traits defined by Scala 2.11
9190
new NonLocalReturns, // Expand non-local returns
9291
new CapturedVars, // Represent vars captured by closures as heap objects
9392
new Constructors, // Collect initialization code in primary constructors
9493
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
9594
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
9695
new GetClass, // Rewrites getClass calls on primitive types.
9796
new Simplify), // Perform local optimizations, simplified versions of what linker does.
98-
List(new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
97+
List(new LinkScala2ImplClasses, // Forward calls to the implementation classes of traits defined by Scala 2.11
98+
new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
9999
// Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
100100
new ElimStaticThis, // Replace `this` references to static objects by global identifiers
101101
new Flatten, // Lift all inner classes to package scope

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ object Flags {
399399
/** A module variable (Scala 2.x only) */
400400
final val Scala2ModuleVar = termFlag(57, "<modulevar>")
401401

402+
/** A Scala 2.12 trait that has been augmented with static members */
403+
final val Scala_2_12_Augmented = typeFlag(57, "<scala12augmented")
404+
402405
/** A definition that's initialized before the super call (Scala 2.x only) */
403406
final val Scala2PreSuper = termFlag(58, "<presuper>")
404407

compiler/src/dotty/tools/dotc/core/NameKinds.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ object NameKinds {
359359
val ExtMethName = new SuffixNameKind(EXTMETH, "$extension")
360360
val ModuleVarName = new SuffixNameKind(OBJECTVAR, "$module")
361361
val ModuleClassName = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass")
362+
val ImplMethName = new SuffixNameKind(IMPLMETH, "$")
362363

363364
/** A name together with a signature. Used in Tasty trees. */
364365
object SignedName extends NameKind(63) {

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ object TastyFormat {
256256
final val OBJECTCLASS = 40
257257

258258
final val SIGNED = 63
259+
259260
final val firstInternalTag = 64
261+
final val IMPLMETH = 64
260262

261263
// AST tags
262264

compiler/src/dotty/tools/dotc/transform/LinkScala2ImplClasses.scala

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,84 @@ import NameOps._
1616
import Phases._
1717
import ast.untpd
1818
import ast.Trees._
19+
import NameKinds.ImplMethName
1920
import collection.mutable
2021

2122
/** Rewrite calls
2223
*
2324
* super[M].f(args)
2425
*
25-
* where M is a Scala2 trait implemented by the current class to
26+
* where M is a Scala 2.11 trait implemented by the current class to
2627
*
2728
* M$class.f(this, args)
2829
*
2930
* provided the implementation class M$class defines a corresponding function `f`.
31+
* If M is a Scala 2.12 or newer trait, rewrite to
32+
*
33+
* M.f(this, args)
34+
*
35+
* where f is a static member of M.
3036
*/
31-
class LinkScala2ImplClasses extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
37+
class LinkScala2ImplClasses extends MiniPhase with IdentityDenotTransformer { thisTransform =>
3238
import ast.tpd._
3339

3440
override def phaseName: String = "linkScala2ImplClasses"
41+
override def changesMembers = true
42+
val treeTransform = new Transform
43+
44+
override def runsAfterGroupsOf: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
45+
// Adds as a side effect static members to traits which can confuse Mixin,
46+
// that's why it is runsAfterGroupOf
3547

36-
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Mixin])
37-
38-
override def transformApply(app: Apply)(implicit ctx: Context, info: TransformerInfo) = {
39-
def currentClass = ctx.owner.enclosingClass.asClass
40-
app match {
41-
case Apply(sel @ Select(Super(_, _), _), args)
42-
if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) =>
43-
val impl = implMethod(sel.symbol)
44-
if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos)
45-
else app // could have been an abstract method in a trait linked to from a super constructor
46-
case _ =>
47-
app
48+
class Transform extends TreeTransform {
49+
def phase = thisTransform
50+
51+
/** Copy definitions from implementation class to trait itself */
52+
private def augmentScala_2_12_Trait(mixin: ClassSymbol)(implicit ctx: Context): Unit = {
53+
def newImpl(sym: TermSymbol): Symbol = sym.copy(
54+
owner = mixin,
55+
name = if (sym.isConstructor) sym.name else ImplMethName(sym.name)
56+
)
57+
for (sym <- mixin.implClass.info.decls)
58+
newImpl(sym.asTerm).enteredAfter(thisTransform)
4859
}
49-
}
5060

51-
private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
52-
val implInfo = meth.owner.implClass.info
53-
if (meth.isConstructor)
54-
implInfo.decl(nme.TRAIT_CONSTRUCTOR).symbol
55-
else
56-
implInfo.decl(meth.name)
57-
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
58-
.symbol
61+
override def prepareForTemplate(impl: Template)(implicit ctx: Context) = {
62+
val cls = impl.symbol.owner.asClass
63+
for (mixin <- cls.mixins)
64+
if (mixin.is(Scala_2_12_Trait, butNot = Scala_2_12_Augmented)) {
65+
augmentScala_2_12_Trait(mixin)
66+
mixin.setFlag(Scala_2_12_Augmented)
67+
}
68+
this
69+
}
70+
71+
override def transformApply(app: Apply)(implicit ctx: Context, info: TransformerInfo) = {
72+
def currentClass = ctx.owner.enclosingClass.asClass
73+
app match {
74+
case Apply(sel @ Select(Super(_, _), _), args)
75+
if sel.symbol.owner.is(Scala2xTrait) && currentClass.mixins.contains(sel.symbol.owner) =>
76+
val impl = implMethod(sel.symbol)
77+
if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withPos(app.pos)
78+
else app // could have been an abstract method in a trait linked to from a super constructor
79+
case _ =>
80+
app
81+
}
82+
}
83+
84+
private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
85+
val (implInfo, implName) =
86+
if (meth.owner.is(Scala_2_12_Trait))
87+
(meth.owner.info, ImplMethName(meth.name.asTermName))
88+
else
89+
(meth.owner.implClass.info, meth.name)
90+
if (meth.isConstructor)
91+
implInfo.decl(nme.TRAIT_CONSTRUCTOR).symbol
92+
else
93+
implInfo.decl(implName)
94+
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
95+
.symbol
96+
}
5997
}
6098

6199
private val Scala2xTrait = allOf(Scala2x, Trait)

0 commit comments

Comments
 (0)