@@ -10,21 +10,25 @@ import Symbols._
10
10
import Types ._
11
11
import Decorators ._
12
12
import DenotTransformers ._
13
+ import Names ._
13
14
import StdNames ._
15
+ import SymDenotations ._
14
16
import ast .Trees ._
15
17
import NameKinds .ImplMethName
16
18
17
19
/** Rewrite calls
18
20
*
19
21
* super[M].f(args)
20
22
*
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
22
24
*
23
25
* M.f$(this, args)
24
26
*
25
27
* where f$ is a static member of M.
28
+ *
29
+ * Also generates said static members, as forwarders to the normal methods.
26
30
*/
27
- class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhase =>
31
+ class LinkScala2Impls extends MiniPhase with SymTransformer { thisPhase =>
28
32
import ast .tpd ._
29
33
30
34
override def phaseName : String = " linkScala2Impls"
@@ -34,47 +38,77 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas
34
38
// Adds as a side effect static members to traits which can confuse Mixin,
35
39
// that's why it is runsAfterGroupOf
36
40
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 ._
40
46
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
+ )
65
58
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
72
106
73
107
override def transformApply (app : Apply )(implicit ctx : Context ): Tree = {
74
108
def currentClass = ctx.owner.enclosingClass.asClass
75
109
app match {
76
110
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 =>
78
112
val impl = implMethod(sel.symbol)
79
113
if (impl.exists) Apply (ref(impl), This (currentClass) :: args).withSpan(app.span)
80
114
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
83
117
}
84
118
}
85
119
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 =
89
122
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
101
129
}
0 commit comments