1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package dotty.tools.dotc
package transform
import core._
import TreeTransforms._
import Contexts.Context
import Flags._
import SymUtils._
import Symbols._
import SymDenotations._
import Types._
import Decorators._
import DenotTransformers._
import StdNames._
import NameOps._
import ast.Trees._
import util.Positions._
import Names._
import collection.mutable
import ResolveSuper._
/** This phase adds super accessors and method overrides where
* linearization differs from Java's rule for default methods in interfaces.
* In particular:
*
* For every trait M directly implemented by the class (see SymUtils.mixin), in
* reverse linearization order, add the following definitions to C:
*
* 3.1 (done in `superAccessors`) For every superAccessor
* `<mods> def super$f[Ts](ps1)...(psN): U` in M:
*
* <mods> def super$f[Ts](ps1)...(psN): U = super[S].f[Ts](ps1)...(psN)
*
* where `S` is the superclass of `M` in the linearization of `C`.
*
* 3.2 (done in `methodOverrides`) For every method
* `<mods> def f[Ts](ps1)...(psN): U` in M` that needs to be disambiguated:
*
* <mods> def f[Ts](ps1)...(psN): U = super[M].f[Ts](ps1)...(psN)
*
* A method in M needs to be disambiguated if it is concrete, not overridden in C,
* and if it overrides another concrete method.
*
* This is the first part of what was the mixin phase. It is complemented by
* Mixin, which runs after erasure.
*/
class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
import ast.tpd._
override def phaseName: String = "resolveSuper"
override def runsAfter = Set(classOf[ElimByName], // verified empirically, need to figure out what the reason is.
classOf[AugmentScala2Traits])
override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
val cls = impl.symbol.owner.asClass
val ops = new MixinOps(cls, thisTransform)
import ops._
def superAccessors(mixin: ClassSymbol): List[Tree] =
for (superAcc <- mixin.info.decls.filter(_ is SuperAccessor).toList)
yield polyDefDef(implementation(superAcc.asTerm), forwarder(rebindSuper(cls, superAcc)))
def methodOverrides(mixin: ClassSymbol): List[Tree] =
for (meth <- mixin.info.decls.toList if needsForwarder(meth))
yield polyDefDef(implementation(meth.asTerm), forwarder(meth))
val overrides = mixins.flatMap(mixin => superAccessors(mixin) ::: methodOverrides(mixin))
cpy.Template(impl)(body = overrides ::: impl.body)
}
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
val meth = ddef.symbol.asTerm
if (meth.is(SuperAccessor, butNot = Deferred)) {
assert(ddef.rhs.isEmpty)
val cls = meth.owner.asClass
val ops = new MixinOps(cls, thisTransform)
import ops._
polyDefDef(meth, forwarder(rebindSuper(cls, meth)))
}
else ddef
}
private val PrivateOrAccessorOrDeferred = Private | Accessor | Deferred
}
object ResolveSuper {
/** Returns the symbol that is accessed by a super-accessor in a mixin composition.
*
* @param base The class in which everything is mixed together
* @param acc The symbol statically referred to by the superaccessor in the trait
*/
def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = {
var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail
var sym: Symbol = NoSymbol
val unexpandedAccName =
if (acc.is(ExpandedName)) // Cannot use unexpandedName because of #765. t2183.scala would fail if we did.
acc.name
.drop(acc.name.indexOfSlice(nme.EXPAND_SEPARATOR ++ nme.SUPER_PREFIX))
.drop(nme.EXPAND_SEPARATOR.length)
else acc.name
val SuperAccessorName(memberName) = unexpandedAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type
ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName")
while (bcs.nonEmpty && sym == NoSymbol) {
val other = bcs.head.info.nonPrivateDecl(memberName)
if (ctx.settings.debug.value)
ctx.log(i"rebindsuper ${bcs.head} $other deferred = ${other.symbol.is(Deferred)}")
sym = other.matchingDenotation(base.thisType, base.thisType.memberInfo(acc)).symbol
bcs = bcs.tail
}
assert(sym.exists)
sym
}
}
|