Skip to content

Commit 4c5b14a

Browse files
committed
New phase: AugmentScala2Traits
1 parent 19295ca commit 4c5b14a

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,15 @@ class Compiler {
5656
new Getters,
5757
new ClassTags,
5858
new ElimByName,
59+
new AugmentScala2Traits,
5960
new ResolveSuper),
6061
List(new Erasure),
6162
List(new ElimErasedValueType,
6263
new VCInline,
6364
new Mixin,
6465
new LazyVals,
6566
new Memoize,
67+
//new LinkScala2ImplClasses,
6668
new CapturedVars, // capturedVars has a transformUnit: no phases should introduce local mutable vars here
6769
new Constructors,
6870
new FunctionalInterfaces),
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import TreeTransforms._
6+
import Contexts.Context
7+
import Flags._
8+
import SymUtils._
9+
import Symbols._
10+
import SymDenotations._
11+
import Types._
12+
import Decorators._
13+
import DenotTransformers._
14+
import StdNames._
15+
import NameOps._
16+
import ast.Trees._
17+
18+
/** This phase augments Scala2 traits with implementation classes and with additional members
19+
* needed for mixin composition.
20+
* These symbols would have been added between Unpickling and Mixin in the Scala2 pipeline.
21+
* Specifcally, it adds
22+
*
23+
* - an implementation class which defines a trait constructor and trait method implementations
24+
* - trait setters for vals defined in traits
25+
*
26+
* Furthermore, it expands the names of all private getters and setters in the trait and makes
27+
* them not-private.
28+
*/
29+
class AugmentScala2Traits extends MiniPhaseTransform with IdentityDenotTransformer with FullParameterization { thisTransform =>
30+
import ast.tpd._
31+
32+
override def phaseName: String = "augmentScala2Traits"
33+
34+
override def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context) = NoSymbol
35+
36+
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
37+
val cls = impl.symbol.owner.asClass
38+
for (mixin <- cls.mixins)
39+
if (mixin.is(Scala2x))
40+
augmentScala2Trait(mixin, cls)
41+
impl
42+
}
43+
44+
private def augmentScala2Trait(mixin: ClassSymbol, cls: ClassSymbol)(implicit ctx: Context): Unit = {
45+
if (mixin.implClass.is(Scala2x)) () // nothing to do, mixin was already augmented
46+
else {
47+
//println(i"creating new implclass for $mixin ${mixin.implClass}")
48+
val ops = new MixinOps(cls, thisTransform)
49+
import ops._
50+
51+
val implClass = ctx.newCompleteClassSymbol(
52+
owner = mixin.owner,
53+
name = mixin.name.implClassName,
54+
flags = Abstract | Scala2x,
55+
parents = defn.ObjectClass.typeRef :: Nil,
56+
assocFile = mixin.assocFile).enteredAfter(thisTransform)
57+
58+
def implMethod(meth: TermSymbol): Symbol = {
59+
val mold =
60+
if (meth.isConstructor)
61+
meth.copySymDenotation(
62+
name = nme.IMPLCLASS_CONSTRUCTOR,
63+
info = MethodType(Nil, defn.UnitType))
64+
else meth.ensureNotPrivate
65+
meth.copy(
66+
owner = implClass,
67+
name = mold.name.asTermName,
68+
flags = Method | JavaStatic | mold.flags & ExpandedName,
69+
info = fullyParameterizedType(mold.info, mixin))
70+
}
71+
72+
def traitSetter(getter: TermSymbol) = {
73+
val separator = if (getter.is(Private)) nme.EXPAND_SEPARATOR else nme.TRAIT_SETTER_SEPARATOR
74+
val expandedGetterName =
75+
if (getter.is(ExpandedName)) getter.name
76+
else getter.name.expandedName(getter.owner, separator)
77+
getter.copy(
78+
name = expandedGetterName.setterName,
79+
flags = Method | Accessor | ExpandedName,
80+
info = MethodType(getter.info.resultType :: Nil, defn.UnitType))
81+
}
82+
83+
for (sym <- mixin.info.decls) {
84+
if (needsForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy))
85+
implClass.enter(implMethod(sym.asTerm))
86+
if (sym.isGetter && !sym.is(LazyOrDeferred) && !sym.setter.exists)
87+
traitSetter(sym.asTerm).enteredAfter(thisTransform)
88+
if (sym.is(PrivateAccessor, butNot = ExpandedName) &&
89+
(sym.isGetter || sym.isSetter)) // strangely, Scala 2 fields are also methods that have Accessor set.
90+
sym.ensureNotPrivate.installAfter(thisTransform)
91+
}
92+
ctx.log(i"Scala2x trait decls of $mixin = ${mixin.info.decls.toList.map(_.showDcl)}%\n %")
93+
ctx.log(i"Scala2x impl decls of $mixin = ${implClass.info.decls.toList.map(_.showDcl)}%\n %")
94+
}
95+
}
96+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th
4848

4949
override def phaseName: String = "resolveSuper"
5050

51-
override def runsAfter = Set(classOf[ElimByName]) // verified empirically, need to figure out what the reason is.
51+
override def runsAfter = Set(classOf[ElimByName], // verified empirically, need to figure out what the reason is.
52+
classOf[AugmentScala2Traits])
5253

5354
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
5455
*

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ class SymUtils(val self: Symbol) extends AnyVal {
8585
def field(implicit ctx: Context): Symbol =
8686
self.owner.info.decl(self.asTerm.name.fieldName).suchThat(!_.is(Method)).symbol
8787

88-
def initializer(implicit ctx: Context): TermSymbol =
89-
self.owner.info.decl(InitializerName(self.asTerm.name)).symbol.asTerm
90-
9188
def isField(implicit ctx: Context): Boolean =
9289
self.isTerm && !self.is(Method)
90+
91+
def implClass(implicit ctx: Context): Symbol =
92+
self.owner.info.decl(self.name.implClassName).symbol
9393
}

0 commit comments

Comments
 (0)