Skip to content

Commit a0b4441

Browse files
committed
wip
1 parent 4f573d0 commit a0b4441

File tree

5 files changed

+102
-57
lines changed

5 files changed

+102
-57
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Compiler {
8888
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
8989
new CollectNullableFields, // Collect fields that can be nulled out after use in lazy initialization
9090
new ElimOuterSelect, // Expand outer selections
91-
new AugmentScala2Traits, // Augments Scala2 traits with additional members needed for mixin composition.
91+
//new AugmentScala2Traits, // Augments Scala2 traits with additional members needed for mixin composition.
9292
new ResolveSuper, // Implement super accessors
9393
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
9494
new ParamForwarding, // Add forwarders for aliases of superclass parameters

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

Lines changed: 78 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,25 @@ import Symbols._
1010
import Types._
1111
import Decorators._
1212
import DenotTransformers._
13+
import Names._
1314
import StdNames._
15+
import SymDenotations._
1416
import ast.Trees._
1517
import NameKinds.ImplMethName
1618

1719
/** Rewrite calls
1820
*
1921
* super[M].f(args)
2022
*
21-
* where M is a Scala 2.x trait implemented by the current class to
23+
* where M is a trait implemented by the current class to
2224
*
2325
* M.f$(this, args)
2426
*
2527
* where f$ is a static member of M.
28+
*
29+
* Also generates said static members, as forwarders to the normal methods.
2630
*/
27-
class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhase =>
31+
class LinkScala2Impls extends MiniPhase with SymTransformer { thisPhase =>
2832
import ast.tpd._
2933

3034
override def phaseName: String = "linkScala2Impls"
@@ -34,47 +38,77 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas
3438
// Adds as a side effect static members to traits which can confuse Mixin,
3539
// that's why it is runsAfterGroupOf
3640

37-
private def addStaticForwarders(mixin: ClassSymbol)(implicit ctx: Context): Unit = {
38-
val ops = new MixinOps(mixin, thisPhase)
39-
import ops._
41+
override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
42+
if sym.is(Trait) && !ctx.settings.scalajs.value then
43+
val mixin = sym.asClass.classSymbol
44+
val ops = new MixinOps(mixin, thisPhase)
45+
import ops._
4046

41-
def newImpl(meth: TermSymbol): Symbol = {
42-
def staticInfo(tp: Type) = tp match {
43-
case mt: MethodType =>
44-
MethodType(nme.SELF :: mt.paramNames, mixin.typeRef :: mt.paramInfos, mt.resType)
45-
}
46-
val mold =
47-
if (meth.isConstructor)
48-
meth.copySymDenotation(
49-
name = nme.TRAIT_CONSTRUCTOR,
50-
info = MethodType(Nil, defn.UnitType))
51-
else meth.ensureNotPrivate
52-
meth.copy(
53-
owner = mixin,
54-
name = if (meth.isConstructor) mold.name.asTermName else ImplMethName(mold.name.asTermName),
55-
flags = Method | JavaStatic,
56-
info = staticInfo(mold.info)
57-
)
58-
}
59-
for (sym <- mixin.info.decls)
60-
if (needsMixinForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred))
61-
newImpl(sym.asTerm).enteredAfter(thisPhase)
62-
// The trait is now fully augmented so the flag isn't needed anymore.
63-
mixin.resetFlag(Scala2xPartiallyAugmented)
64-
}
47+
def newImpl(meth: TermSymbol): Symbol =
48+
def staticInfo(tp: Type) = tp match
49+
case mt: MethodType =>
50+
MethodType(nme.SELF :: mt.paramNames, mixin.typeRef :: mt.paramInfos, mt.resType)
51+
val mold = meth.ensureNotPrivate
52+
meth.copy(
53+
owner = mixin,
54+
name = staticForwarderName(mold.name.asTermName),
55+
flags = Method | JavaStatic,
56+
info = staticInfo(mold.info)
57+
)
6558

66-
override def prepareForTemplate(impl: Template)(implicit ctx: Context): Context = {
67-
val cls = impl.symbol.owner.asClass
68-
for (mixin <- cls.mixins if (mixin.is(Scala2xPartiallyAugmented)))
69-
addStaticForwarders(mixin)
70-
ctx
71-
}
59+
val classInfo = sym.asClass.classInfo
60+
val decls1 = classInfo.decls.cloneScope
61+
var modified: Boolean = false
62+
for (meth <- classInfo.decls)
63+
if needsStaticForwarder(meth) then
64+
decls1.enter(newImpl(meth.asTerm))
65+
modified = true
66+
if modified then
67+
sym.copySymDenotation(
68+
info = classInfo.derivedClassInfo(decls = decls1))
69+
else
70+
sym
71+
else
72+
sym
73+
end transformSym
74+
75+
private def needsStaticForwarder(sym: Symbol)(implicit ctx: Context): Boolean =
76+
sym.is(Method, butNot = Deferred)
77+
78+
private def staticForwarderName(name: TermName)(implicit ctx: Context): TermName =
79+
if name == nme.TRAIT_CONSTRUCTOR then name
80+
else ImplMethName(name)
81+
82+
override def transformTemplate(impl: Template)(implicit ctx: Context): Tree =
83+
val sym = impl.symbol.owner.asClass
84+
if sym.is(Trait) && !ctx.settings.scalajs.value then
85+
val newConstr :: newBody = (impl.constr :: impl.body).flatMap {
86+
case stat: DefDef if needsStaticForwarder(stat.symbol) =>
87+
val meth = stat.symbol
88+
val staticForwarderDef = DefDef(implMethod(meth).asTerm, { paramss =>
89+
val params = paramss.head
90+
/* FIXME This is wrong. We are emitting a virtual call to `meth`,
91+
* but we must instead emit an `invokespecial` so that it is not
92+
* virtual. However, I don't know how to represent an invokevirtual
93+
* call on a non-`this` receiver. My best attempt is the following,
94+
* but that throws an exception when type-assigning the Super node:
95+
*/
96+
//Apply(Super(params.head, sym.name.asTypeName, sym).select(meth), params.tail)
97+
Apply(params.head.select(meth), params.tail)
98+
})
99+
stat :: transformFollowing(staticForwarderDef) :: Nil
100+
case stat =>
101+
stat :: Nil
102+
}
103+
cpy.Template(impl)(constr = newConstr.asInstanceOf[DefDef], body = newBody)
104+
else
105+
impl
72106

73107
override def transformApply(app: Apply)(implicit ctx: Context): Tree = {
74108
def currentClass = ctx.owner.enclosingClass.asClass
75109
app match {
76110
case Apply(sel @ Select(Super(_, _), _), args)
77-
if sel.symbol.owner.is(Scala2x) && currentClass.mixins.contains(sel.symbol.owner) && !ctx.settings.scalajs.value =>
111+
if sel.symbol.owner.is(Trait) && currentClass.mixins.contains(sel.symbol.owner) && !ctx.settings.scalajs.value =>
78112
val impl = implMethod(sel.symbol)
79113
if (impl.exists) Apply(ref(impl), This(currentClass) :: args).withSpan(app.span)
80114
else app // could have been an abstract method in a trait linked to from a super constructor
@@ -83,19 +117,13 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas
83117
}
84118
}
85119

86-
/** The 2.12 implementation method of a super call or implementation class target */
87-
private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol = {
88-
val implName = ImplMethName(meth.name.asTermName)
120+
/** The implementation method of a super call or implementation class target */
121+
private def implMethod(meth: Symbol)(implicit ctx: Context): Symbol =
89122
val cls = meth.owner
90-
if (cls.isAllOf(Scala2xTrait))
91-
if (meth.isConstructor)
92-
cls.info.decl(nme.TRAIT_CONSTRUCTOR).symbol
93-
else
94-
cls.info.decl(implName)
95-
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
96-
.symbol
97-
else throw new AssertionError(i"no impl method for $meth")
98-
}
99-
100-
private val Scala2xTrait = Scala2x | Trait
123+
if meth.name == nme.TRAIT_CONSTRUCTOR then
124+
cls.info.decl(nme.TRAIT_CONSTRUCTOR).suchThat(_.is(JavaStatic)).symbol
125+
else
126+
cls.info.decl(staticForwarderName(meth.name.asTermName))
127+
.suchThat(c => FullParameterization.memberSignature(c.info) == meth.signature)
128+
.symbol
101129
}

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

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,27 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
130130
else sym.copySymDenotation(initFlags = sym.flags &~ ParamAccessor | Deferred)
131131
sym1.ensureNotPrivate
132132
}
133-
else if (sym.isConstructor && (sym.owner.is(Trait, butNot = Scala2x) || (sym.owner.isAllOf(Trait | Scala2x) && ctx.settings.scalajs.value)))
133+
else if (sym.isConstructor && sym.owner.is(Trait))
134134
sym.copySymDenotation(
135135
name = nme.TRAIT_CONSTRUCTOR,
136136
info = MethodType(Nil, sym.info.resultType))
137+
else if sym.is(Trait) then
138+
val classInfo = sym.asClass.classInfo
139+
val decls1 = classInfo.decls.cloneScope
140+
var modified: Boolean = false
141+
for (getter <- classInfo.decls)
142+
if needsTraitSetter(getter) then
143+
val setter = makeTraitSetter(getter.asTerm)
144+
decls1.enter(setter)
145+
modified = true
146+
if modified then
147+
sym.copySymDenotation(
148+
info = classInfo.derivedClassInfo(decls = decls1))
149+
else
150+
sym
137151
else
138152
sym
153+
end transformSym
139154

140155
private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = {
141156
if (sym.is(Lazy)) sym
@@ -159,7 +174,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
159174
sym.isGetter && !wasOneOf(sym, DeferredOrLazy | ParamAccessor) && !sym.setter.exists
160175
&& !sym.info.resultType.isInstanceOf[ConstantType]
161176

162-
private def traitSetter(getter: TermSymbol)(implicit ctx: Context): Symbol =
177+
private def makeTraitSetter(getter: TermSymbol)(implicit ctx: Context): Symbol =
163178
getter.copy(
164179
name = Mixin.traitSetterName(getter),
165180
flags = Method | Accessor | Deferred,
@@ -174,9 +189,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
174189
stats.flatMap {
175190
case stat: DefDef if needsTraitSetter(stat.symbol) =>
176191
// add a trait setter for this getter
177-
val vsym = stat.symbol.asTerm
178-
val ssym = traitSetter(vsym).asTerm.enteredAfter(thisPhase)
179-
stat :: DefDef(ssym, EmptyTree) :: Nil
192+
stat :: DefDef(stat.symbol.traitSetter.asTerm, EmptyTree) :: Nil
180193
case stat: DefDef if stat.symbol.isSetter =>
181194
cpy.DefDef(stat)(rhs = EmptyTree) :: Nil
182195
case stat =>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase =
3434
override def phaseName: String = ResolveSuper.name
3535

3636
override def runsAfter: Set[String] = Set(ElimByName.name, // verified empirically, need to figure out what the reason is.
37-
AugmentScala2Traits.name,
37+
//AugmentScala2Traits.name,
3838
PruneErasedDefs.name) // Erased decls make `isCurrent` work incorrectly
3939

4040
override def changesMembers: Boolean = true // the phase adds super accessors

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ class SymUtils(val self: Symbol) extends AnyVal {
152152
if (self.isSetter) self
153153
else accessorNamed(self.asTerm.name.setterName)
154154

155+
def traitSetter(implicit ctx: Context): Symbol =
156+
if (self.name.is(TraitSetterName)) self
157+
else accessorNamed(Mixin.traitSetterName(self.asTerm))
158+
155159
def field(implicit ctx: Context): Symbol = {
156160
val thisName = self.name.asTermName
157161
val fieldName =

0 commit comments

Comments
 (0)