Skip to content

Commit 764c1f6

Browse files
committed
New Mixin scheme.
Split into two phases, ResolveSuper before Erasure and Mixin after. Likewise GettersSetters is split into Getters and Memoize. All tests pass, except two tests fail when compiled twice. Will investigate next why.
1 parent 98bd575 commit 764c1f6

File tree

7 files changed

+365
-171
lines changed

7 files changed

+365
-171
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ class Compiler {
5050
new Splitter),
5151
List(new ElimByName,
5252
new InterceptedMethods,
53-
new Literalize),
54-
List(new Mixin),
55-
List(new GettersSetters),
53+
new Literalize,
54+
new Getters),
55+
List(new ResolveSuper),
5656
List(new Erasure),
57+
List(new Mixin),
58+
List(new Memoize),
5759
List(new CapturedVars,
5860
new Constructors),
5961
List(new LambdaLift,
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.SymTransformer
6+
import Contexts.Context
7+
import SymDenotations.SymDenotation
8+
import Types._
9+
import Symbols._
10+
import SymUtils._
11+
import Constants._
12+
import TreeTransforms._
13+
import Flags._
14+
import Decorators._
15+
16+
/** Performs the following rewritings for fields of a class:
17+
*
18+
* <mods> val x: T = e
19+
* --> <mods> <stable> def x: T = e
20+
* <mods> var x: T = e
21+
* --> <mods> def x: T = e
22+
*
23+
* <mods> val x: T
24+
* --> <mods> <stable> def x: T
25+
*
26+
* <mods> var x: T
27+
* --> <mods> def x: T
28+
*
29+
* Omitted from the rewritings are
30+
*
31+
* - private[this] fields in non-trait classes
32+
* - fields generated for static modules (TODO: needed?)
33+
* - parameters, static fields, and fields coming from Java
34+
*
35+
* Furthermore, assignements to mutable vars are replaced by setter calls
36+
*
37+
* p.x = e
38+
* --> p.x_=(e)
39+
*/
40+
class Getters extends MiniPhaseTransform with SymTransformer { thisTransform =>
41+
import ast.tpd._
42+
43+
override def phaseName = "getters"
44+
override def treeTransformPhase = thisTransform.next
45+
46+
override def transformSym(d: SymDenotation)(implicit ctx: Context): SymDenotation = {
47+
def noGetterNeeded =
48+
d.is(NoGetterNeeded) ||
49+
d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) ||
50+
d.is(Module) && d.isStatic ||
51+
d.isSelfSym
52+
if (d.isTerm && d.owner.isClass && d.info.isValueType && !noGetterNeeded) {
53+
val maybeStable = if (d.isStable) Stable else EmptyFlags
54+
d.copySymDenotation(
55+
initFlags = d.flags | maybeStable | AccessorCreationFlags,
56+
info = ExprType(d.info))
57+
}
58+
else d
59+
}
60+
private val NoGetterNeeded = Method | Param | JavaDefined | JavaStatic
61+
62+
override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree =
63+
if (tree.symbol is Method) DefDef(tree.symbol.asTerm, tree.rhs) else tree
64+
65+
override def transformAssign(tree: Assign)(implicit ctx: Context, info: TransformerInfo): Tree =
66+
if (tree.lhs.symbol is Method) tree.lhs.becomes(tree.rhs) else tree
67+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers._
6+
import Phases.Phase
7+
import Contexts.Context
8+
import SymDenotations.SymDenotation
9+
import Types._
10+
import Symbols._
11+
import SymUtils._
12+
import Constants._
13+
import ast.Trees._
14+
import TreeTransforms._
15+
import NameOps._
16+
import Flags._
17+
import Decorators._
18+
19+
/** Provides the implementations of all getters and setters, introducing
20+
* fields to hold the value accessed by them.
21+
* TODO: Make LazyVals a part of this phase?
22+
*
23+
* <accessor> <stable> <mods> def x(): T = e
24+
* --> private val x: T = e
25+
* <accessor> <stable> <mods> def x(): T = x
26+
*
27+
* <accessor> <mods> def x(): T = e
28+
* --> private var x: T = e
29+
* <accessor> <mods> def x(): T = x
30+
*
31+
* <accessor> <mods> def x_=(y: T): Unit = ()
32+
* --> <accessor> <mods> def x_=(y: T): Unit = x = y
33+
*/
34+
class Memoize extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
35+
import ast.tpd._
36+
37+
override def phaseName = "memoize"
38+
override def treeTransformPhase = thisTransform.next
39+
40+
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
41+
val sym = tree.symbol
42+
if (sym.is(Accessor, butNot = NoFieldNeeded))
43+
if (sym.isGetter) {
44+
val maybeMutable = if (sym is Stable) EmptyFlags else Mutable
45+
println(i"add field for $sym")
46+
val field = ctx.newSymbol(
47+
owner = ctx.owner,
48+
name = sym.name.asTermName.fieldName,
49+
flags = Private | maybeMutable,
50+
info = sym.info.resultType,
51+
coord = tree.pos).enteredAfter(thisTransform)
52+
var fieldInit = tree.rhs.changeOwner(sym, field)
53+
val fieldDef = ValDef(field, fieldInit)
54+
val getterDef = cpy.DefDef(tree)(rhs = ref(field))
55+
Thicket(fieldDef, getterDef)
56+
}
57+
else if (sym.isSetter) {
58+
val Literal(Constant(())) = tree.rhs
59+
assert(sym.field.exists, i"no field for ${sym.showLocated} in ${sym.owner.info.decls.toList.map{_.showDcl}}%; %")
60+
val initializer = Assign(ref(sym.field), ref(tree.vparamss.head.head.symbol))
61+
cpy.DefDef(tree)(rhs = initializer)
62+
}
63+
else tree // curiously, some accessors from Scala2 have ' ' suffixes. They count as
64+
// neither getters nor setters
65+
else tree
66+
}
67+
private val NoFieldNeeded = Lazy | Deferred | ParamAccessor
68+
}

0 commit comments

Comments
 (0)