1
1
package dotty .tools .dotc .transform
2
2
3
3
import dotty .tools .dotc .ast .Trees ._
4
- import dotty .tools .dotc .ast .tpd
4
+ import dotty .tools .dotc .ast .{ TreeTypeMap , tpd }
5
5
import dotty .tools .dotc .core .Contexts .Context
6
6
import dotty .tools .dotc .core .Decorators ._
7
7
import dotty .tools .dotc .core .DenotTransformers .DenotTransformer
@@ -10,13 +10,12 @@ import dotty.tools.dotc.core.Symbols._
10
10
import dotty .tools .dotc .core .Types ._
11
11
import dotty .tools .dotc .core ._
12
12
import dotty .tools .dotc .transform .TailRec ._
13
- import dotty .tools .dotc .transform .TreeTransforms .{TransformerInfo , MiniPhaseTransform }
13
+ import dotty .tools .dotc .transform .TreeTransforms .{MiniPhaseTransform , TransformerInfo }
14
14
15
15
/**
16
16
* A Tail Rec Transformer
17
- *
18
17
* @author Erik Stenman, Iulian Dragos,
19
- * ported to dotty by Dmitry Petrashko
18
+ * ported and heavily modified for dotty by Dmitry Petrashko
20
19
* @version 1.1
21
20
*
22
21
* What it does:
@@ -77,7 +76,9 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
77
76
private def mkLabel (method : Symbol , abstractOverClass : Boolean )(implicit c : Context ): TermSymbol = {
78
77
val name = c.freshName(labelPrefix)
79
78
80
- c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = true ))
79
+ if (method.owner.isClass)
80
+ c.newSymbol(method, name.toTermName, labelFlags, fullyParameterizedType(method.info, method.enclosingClass.asClass, abstractOverClass, liftThisType = false ))
81
+ else c.newSymbol(method, name.toTermName, labelFlags, method.info)
81
82
}
82
83
83
84
override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context , info : TransformerInfo ): tpd.Tree = {
@@ -103,18 +104,33 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
103
104
// and second one will actually apply,
104
105
// now this speculatively transforms tree and throws away result in many cases
105
106
val rhsSemiTransformed = {
106
- val transformer = new TailRecElimination (origMeth, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
107
+ val transformer = new TailRecElimination (origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
107
108
val rhs = atGroupEnd(transformer.transform(dd.rhs)(_))
108
109
rewrote = transformer.rewrote
109
110
rhs
110
111
}
111
112
112
113
if (rewrote) {
113
114
val dummyDefDef = cpy.DefDef (tree)(rhs = rhsSemiTransformed)
114
- val res = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel)
115
- val call = forwarder(label, dd, abstractOverClass = defIsTopLevel, liftThisType = true )
116
- Block (List (res), call)
117
- } else {
115
+ if (tree.symbol.owner.isClass) {
116
+ val labelDef = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel)
117
+ val call = forwarder(label, dd, abstractOverClass = defIsTopLevel, liftThisType = true )
118
+ Block (List (labelDef), call)
119
+ } else { // inner method. Tail recursion does not change `this`
120
+ val labelDef = polyDefDef(label, trefs => vrefss => {
121
+ val origMeth = tree.symbol
122
+ val origTParams = tree.tparams.map(_.symbol)
123
+ val origVParams = tree.vparamss.flatten map (_.symbol)
124
+ new TreeTypeMap (
125
+ typeMap = identity(_)
126
+ .substDealias(origTParams, trefs)
127
+ .subst(origVParams, vrefss.flatten.map(_.tpe)),
128
+ oldOwners = origMeth :: Nil ,
129
+ newOwners = label :: Nil
130
+ ).transform(rhsSemiTransformed)
131
+ })
132
+ Block (List (labelDef), ref(label).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol)))))
133
+ }} else {
118
134
if (mandatory)
119
135
ctx.error(" TailRec optimisation not applicable, method not tail recursive" , dd.pos)
120
136
dd.rhs
@@ -132,7 +148,7 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
132
148
133
149
}
134
150
135
- class TailRecElimination (method : Symbol , enclosingClass : Symbol , thisType : Type , isMandatory : Boolean , label : Symbol , abstractOverClass : Boolean ) extends tpd.TreeMap {
151
+ class TailRecElimination (method : Symbol , methTparams : List [ Tree ], enclosingClass : Symbol , thisType : Type , isMandatory : Boolean , label : Symbol , abstractOverClass : Boolean ) extends tpd.TreeMap {
136
152
137
153
import dotty .tools .dotc .ast .tpd ._
138
154
@@ -217,13 +233,13 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
217
233
} else targs
218
234
219
235
val method = if (callTargs.nonEmpty) TypeApply (Ident (label.termRef), callTargs) else Ident (label.termRef)
220
- val thisPassed = method appliedTo(receiver.ensureConforms(method.tpe.widen.firstParamTypes.head))
236
+ val thisPassed = if ( this . method.owner.isClass) method appliedTo(receiver.ensureConforms(method.tpe.widen.firstParamTypes.head)) else method
221
237
222
238
val res =
223
- if (thisPassed.tpe.widen.isParameterless) thisPassed
224
- else argumentss.foldLeft(thisPassed) {
225
- (met, ar) => Apply (met, ar) // Dotty deviation no auto-detupling yet.
226
- }
239
+ if (thisPassed.tpe.widen.isParameterless) thisPassed
240
+ else argumentss.foldLeft(thisPassed) {
241
+ (met, ar) => Apply (met, ar) // Dotty deviation no auto-detupling yet.
242
+ }
227
243
res
228
244
}
229
245
0 commit comments