1
1
package dotty .tools .dotc .transform
2
2
3
- import dotty .tools .dotc .transform . TreeTransforms .{ TransformerInfo , TreeTransform , TreeTransformer }
4
- import dotty .tools .dotc .ast .{ Trees , tpd }
3
+ import dotty .tools .dotc .ast . Trees . _
4
+ import dotty .tools .dotc .ast .tpd
5
5
import dotty .tools .dotc .core .Contexts .Context
6
- import scala .collection .mutable .ListBuffer
7
- import dotty .tools .dotc .core ._
8
- import dotty .tools .dotc .core .Symbols .NoSymbol
9
- import scala .annotation .tailrec
10
- import Types ._ , Contexts ._ , Constants ._ , Names ._ , NameOps ._ , Flags ._
11
- import SymDenotations ._ , Symbols ._ , StdNames ._ , Annotations ._ , Trees ._
12
- import Decorators ._
13
- import Symbols ._
14
- import scala .Some
15
- import dotty .tools .dotc .transform .TreeTransforms .{NXTransformations , TransformerInfo , TreeTransform , TreeTransformer }
16
- import dotty .tools .dotc .core .Contexts .Context
17
- import scala .collection .mutable
18
- import dotty .tools .dotc .core .Names .Name
19
- import NameOps ._
20
- import dotty .tools .dotc .CompilationUnit
21
- import dotty .tools .dotc .util .Positions .{Position , Coord }
22
- import dotty .tools .dotc .util .Positions .NoPosition
6
+ import dotty .tools .dotc .core .Decorators ._
23
7
import dotty .tools .dotc .core .DenotTransformers .DenotTransformer
24
8
import dotty .tools .dotc .core .Denotations .SingleDenotation
9
+ import dotty .tools .dotc .core .Symbols ._
10
+ import dotty .tools .dotc .core .Types ._
11
+ import dotty .tools .dotc .core ._
25
12
import dotty .tools .dotc .transform .TailRec ._
13
+ import dotty .tools .dotc .transform .TreeTransforms .{TransformerInfo , TreeTransform }
26
14
27
15
/**
28
16
* A Tail Rec Transformer
@@ -74,9 +62,9 @@ import dotty.tools.dotc.transform.TailRec._
74
62
* self recursive functions, that's why it's renamed to tailrec
75
63
* </p>
76
64
*/
77
- class TailRec extends TreeTransform with DenotTransformer {
65
+ class TailRec extends TreeTransform with DenotTransformer with FullParameterization {
78
66
79
- import tpd ._
67
+ import dotty . tools . dotc . ast . tpd ._
80
68
81
69
override def transform (ref : SingleDenotation )(implicit ctx : Context ): SingleDenotation = ref
82
70
@@ -85,54 +73,44 @@ class TailRec extends TreeTransform with DenotTransformer {
85
73
final val labelPrefix = " tailLabel"
86
74
final val labelFlags = Flags .Synthetic | Flags .Label
87
75
88
- private def mkLabel (method : Symbol , tp : Type )(implicit c : Context ): TermSymbol = {
76
+ private def mkLabel (method : Symbol )(implicit c : Context ): TermSymbol = {
89
77
val name = c.freshName(labelPrefix)
90
- c.newSymbol(method, name.toTermName, labelFlags , tp)
78
+
79
+ c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass))
91
80
}
92
81
93
82
override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context , info : TransformerInfo ): tpd.Tree = {
94
83
tree match {
95
84
case dd@ DefDef (mods, name, tparams, vparamss0, tpt, rhs0)
96
- if (dd.symbol.isEffectivelyFinal) && ! ((dd.symbol is Flags .Accessor ) || (rhs0 eq EmptyTree )) =>
85
+ if (dd.symbol.isEffectivelyFinal) && ! ((dd.symbol is Flags .Accessor ) || (rhs0 eq EmptyTree ) || (dd.symbol is Flags . Label ) ) =>
97
86
val mandatory = dd.symbol.hasAnnotation(defn.TailrecAnnotationClass )
98
87
cpy.DefDef (tree, mods, name, tparams, vparamss0, tpt, rhs = {
99
- val owner = ctx.owner.enclosingClass.asClass
100
88
101
- val thisTpe = owner.thisType
102
-
103
- val newType : Type = dd.tpe.widen match {
104
- case t : PolyType => PolyType (t.paramNames)(x => t.paramBounds,
105
- x => MethodType (List (nme.THIS ), List (thisTpe), t.resultType))
106
- case t => MethodType (List (nme.THIS ), List (thisTpe), t)
107
- }
89
+ val origMeth = tree.symbol
90
+ val label = mkLabel(dd.symbol)
91
+ val owner = ctx.owner.enclosingClass.asClass
92
+ val thisTpe = owner.thisType.widen
108
93
109
- val label = mkLabel(dd.symbol, newType)
110
94
var rewrote = false
111
95
112
96
// Note: this can be split in two separate transforms(in different groups),
113
97
// than first one will collect info about which transformations and rewritings should be applied
114
98
// and second one will actually apply,
115
99
// now this speculatively transforms tree and throws away result in many cases
116
- val res = tpd.DefDef (label, args => {
117
- val thiz = args.head.head
118
- val argMapping : Map [Symbol , Tree ] = (vparamss0.flatten.map(_.symbol) zip args.tail.flatten).toMap
119
- val transformer = new TailRecElimination (dd.symbol, thiz, argMapping, owner, mandatory, label)
100
+ val rhsSemiTransformed = {
101
+ val transformer = new TailRecElimination (dd.symbol, owner, thisTpe, mandatory, label)
120
102
val rhs = transformer.transform(rhs0)(ctx.withPhase(ctx.phase.next))
121
103
rewrote = transformer.rewrote
122
104
rhs
123
- })
105
+ }
124
106
125
107
if (rewrote) {
126
- val call =
127
- if (tparams.isEmpty) Ident (label.termRef)
128
- else TypeApply (Ident (label.termRef), tparams)
129
- Block (
130
- List (res),
131
- vparamss0.foldLeft(Apply (call, List (This (owner))))
132
- {(call, args) => Apply (call, args.map(x => Ident (x.symbol.termRef)))}
133
- )
134
- }
135
- else {
108
+ val dummyDefDef = cpy.DefDef (tree, dd.mods, dd.name, dd.tparams, dd.vparamss, dd.tpt,
109
+ rhsSemiTransformed)
110
+ val res = fullyParameterizedDef(label, dummyDefDef)
111
+ val call = forwarder(label, dd)
112
+ Block (List (res), call)
113
+ } else {
136
114
if (mandatory)
137
115
ctx.error(" TailRec optimisation not applicable, method not tail recursive" , dd.pos)
138
116
rhs0
@@ -149,11 +127,9 @@ class TailRec extends TreeTransform with DenotTransformer {
149
127
150
128
}
151
129
152
- class TailRecElimination (method : Symbol , thiz : Tree , argMapping : Map [Symbol , Tree ],
153
- enclosingClass : Symbol , isMandatory : Boolean , label : Symbol ) extends tpd.TreeMap {
154
-
155
- import tpd ._
130
+ class TailRecElimination (method : Symbol , enclosingClass : Symbol , thisType : Type , isMandatory : Boolean , label : Symbol ) extends tpd.RetypingTreeMap {
156
131
132
+ import dotty .tools .dotc .ast .tpd ._
157
133
158
134
var rewrote = false
159
135
@@ -182,7 +158,6 @@ class TailRec extends TreeTransform with DenotTransformer {
182
158
def noTailTransforms (trees : List [Tree ])(implicit c : Context ) =
183
159
trees map (noTailTransform)
184
160
185
-
186
161
override def transform (tree : Tree )(implicit c : Context ): Tree = {
187
162
/* A possibly polymorphic apply to be considered for tail call transformation. */
188
163
def rewriteApply (tree : Tree , sym : Symbol ): Tree = {
@@ -204,7 +179,7 @@ class TailRec extends TreeTransform with DenotTransformer {
204
179
205
180
val receiverIsSame = enclosingClass.typeRef.widen =:= recv.tpe.widen
206
181
val receiverIsSuper = (method.name eq sym) && enclosingClass.typeRef.widen <:< recv.tpe.widen
207
- val receiverIsThis = recv.tpe.widen =:= thiz.tpe.widen
182
+ val receiverIsThis = recv.tpe.widen =:= thisType
208
183
209
184
val isRecursiveCall = (method eq sym)
210
185
@@ -226,17 +201,24 @@ class TailRec extends TreeTransform with DenotTransformer {
226
201
def rewriteTailCall (recv : Tree ): Tree = {
227
202
c.debuglog(" Rewriting tail recursive call: " + tree.pos)
228
203
rewrote = true
229
- val method = if (targs.nonEmpty) TypeApply (Ident (label.termRef), targs) else Ident (label.termRef)
230
- val recv = noTailTransform(reciever)
231
- if (recv.tpe.widen.isParameterless) method
232
- else argumentss.foldLeft(Apply (method, List (recv))) {
233
- (method, args) => Apply (method, args) // Dotty deviation no auto-detupling yet.
204
+ val reciever = noTailTransform(recv)
205
+ val classTypeArgs = recv.tpe.baseTypeWithArgs(enclosingClass).argInfos
206
+ val trz = classTypeArgs.map(x => ref(x.typeSymbol))
207
+ val callTargs : List [tpd.Tree ] = targs ::: trz
208
+ val method = Apply (if (callTargs.nonEmpty) TypeApply (Ident (label.termRef), callTargs) else Ident (label.termRef),
209
+ List (reciever))
210
+
211
+ val res =
212
+ if (method.tpe.widen.isParameterless) method
213
+ else argumentss.foldLeft(method) {
214
+ (met, ar) => Apply (met, ar) // Dotty deviation no auto-detupling yet.
234
215
}
216
+ res
235
217
}
236
218
237
219
if (isRecursiveCall) {
238
220
if (ctx.tailPos) {
239
- if (recv eq EmptyTree ) rewriteTailCall(thiz )
221
+ if (recv eq EmptyTree ) rewriteTailCall(This (enclosingClass.asClass) )
240
222
else if (receiverIsSame || receiverIsThis) rewriteTailCall(recv)
241
223
else fail(" it changes type of 'this' on a polymorphic recursive call" )
242
224
}
@@ -247,7 +229,7 @@ class TailRec extends TreeTransform with DenotTransformer {
247
229
}
248
230
}
249
231
250
- def rewriteTry (tree : Try ): Tree = {
232
+ def rewriteTry (tree : Try ): Try = {
251
233
def transformHandlers (t : Tree ): Tree = {
252
234
t match {
253
235
case Block (List ((d : DefDef )), cl@ Closure (Nil , _, EmptyTree )) =>
@@ -274,65 +256,61 @@ class TailRec extends TreeTransform with DenotTransformer {
274
256
}
275
257
276
258
val res : Tree = tree match {
277
- case Block (stats, expr) =>
278
- tpd.cpy.Block (tree,
259
+
260
+ case tree@ Block (stats, expr) =>
261
+ val tree1 = tpd.cpy.Block (tree,
279
262
noTailTransforms(stats),
280
263
transform(expr)
281
264
)
265
+ propagateType(tree, tree1)
282
266
283
- case t@ CaseDef (pat, guard, body) =>
284
- cpy.CaseDef (t, pat, guard, transform(body))
267
+ case tree@ CaseDef (pat, guard, body) =>
268
+ val tree1 = cpy.CaseDef (tree, pat, guard, transform(body))
269
+ propagateType(tree, tree1)
285
270
286
- case If (cond, thenp, elsep) =>
287
- tpd.cpy.If (tree,
288
- transform (cond),
271
+ case tree @ If (cond, thenp, elsep) =>
272
+ val tree1 = tpd.cpy.If (tree,
273
+ noTailTransform (cond),
289
274
transform(thenp),
290
275
transform(elsep)
291
276
)
277
+ propagateType(tree, tree1)
292
278
293
- case Match (selector, cases) =>
294
- tpd.cpy.Match (tree,
279
+ case tree @ Match (selector, cases) =>
280
+ val tree1 = tpd.cpy.Match (tree,
295
281
noTailTransform(selector),
296
282
transformSub(cases)
297
283
)
284
+ propagateType(tree, tree1)
298
285
299
- case t : Try =>
300
- rewriteTry(t)
286
+ case tree : Try =>
287
+ val tree1 = rewriteTry(tree)
288
+ propagateType(tree, tree1)
301
289
302
290
case Apply (fun, args) if fun.symbol == defn.Boolean_or || fun.symbol == defn.Boolean_and =>
303
291
tpd.cpy.Apply (tree, fun, transform(args))
304
292
305
293
case Apply (fun, args) =>
306
294
rewriteApply(tree, fun.symbol)
295
+
307
296
case Alternative (_) | Bind (_, _) =>
308
297
assert(false , " We should've never gotten inside a pattern" )
309
298
tree
310
- case This (cls) if cls eq enclosingClass =>
311
- thiz
312
- case Select (qual, name) =>
299
+
300
+ case tree : Select =>
313
301
val sym = tree.symbol
314
302
if (sym == method && ctx.tailPos) rewriteApply(tree, sym)
315
- else tpd.cpy.Select (tree, noTailTransform(qual), name)
303
+ else propagateType(tree, tpd.cpy.Select (tree, noTailTransform(tree.qualifier), tree.name))
304
+
316
305
case ValDef (_, _, _, _) | EmptyTree | Super (_, _) | This (_) |
317
306
Literal (_) | TypeTree (_) | DefDef (_, _, _, _, _, _) | TypeDef (_, _, _) =>
318
307
tree
308
+
319
309
case Ident (qual) =>
320
310
val sym = tree.symbol
321
311
if (sym == method && ctx.tailPos) rewriteApply(tree, sym)
322
- else argMapping.get(sym) match {
323
- case Some (rewrite) => rewrite
324
- case None => tree.tpe match {
325
- case TermRef (ThisType (`enclosingClass`), _) =>
326
- if (sym.flags is Flags .Local ) {
327
- // trying to access private[this] member. toggle flag in order to access.
328
- val d = sym.denot
329
- val newDenot = d.copySymDenotation(initFlags = sym.flags &~ Flags .Local )
330
- newDenot.installAfter(TailRec .this )
331
- }
332
- thiz.select(sym)
333
- case _ => tree
334
- }
335
- }
312
+ else tree
313
+
336
314
case _ =>
337
315
super .transform(tree)
338
316
}
@@ -341,6 +319,11 @@ class TailRec extends TreeTransform with DenotTransformer {
341
319
}
342
320
}
343
321
322
+ /** If references to original `target` from fully parameterized method `derived` should be
323
+ * rewired to some fully parameterized method, that method symbol,
324
+ * otherwise NoSymbol.
325
+ */
326
+ override protected def rewiredTarget (target : Symbol , derived : Symbol )(implicit ctx : Context ): Symbol = NoSymbol
344
327
}
345
328
346
329
object TailRec {
0 commit comments