@@ -6,7 +6,6 @@ import ast.{TreeTypeMap, tpd}
6
6
import core ._
7
7
import Contexts .Context
8
8
import Decorators ._
9
- import DenotTransformers .DenotTransformer
10
9
import Denotations .SingleDenotation
11
10
import Symbols ._
12
11
import Types ._
@@ -62,13 +61,11 @@ import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
62
61
* self recursive functions, that's why it's renamed to tailrec
63
62
* </p>
64
63
*/
65
- class TailRec extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransform =>
64
+ class TailRec extends MiniPhaseTransform with FullParameterization { thisTransform =>
66
65
import TailRec ._
67
66
68
67
import dotty .tools .dotc .ast .tpd ._
69
68
70
- override def transform (ref : SingleDenotation )(implicit ctx : Context ): SingleDenotation = ref
71
-
72
69
override def phaseName : String = " tailrec"
73
70
74
71
override def treeTransformPhase (implicit ctx : Context , info : TransformerInfo ) =
@@ -98,71 +95,69 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
98
95
else ctx.newSymbol(method, name.toTermName, labelFlags, method.info)
99
96
}
100
97
98
+ /** Note: This method should be run atGroupEnd */
101
99
override def transformDefDef (tree : tpd.DefDef )(implicit ctx : Context , info : TransformerInfo ): tpd.Tree = {
102
100
val sym = tree.symbol
103
101
tree match {
104
102
case dd@ DefDef (name, tparams, vparamss0, tpt, _)
105
103
if (sym.isEffectivelyFinal) && ! ((sym is Flags .Accessor ) || (dd.rhs eq EmptyTree ) || (sym is Flags .Label )) =>
106
104
val mandatory = sym.hasAnnotation(defn.TailrecAnnot )
107
- atGroupEnd { implicit ctx : Context =>
108
-
109
- cpy.DefDef (dd)(rhs = {
110
-
111
- val defIsTopLevel = sym.owner.isClass
112
- val origMeth = sym
113
- val label = mkLabel(sym, abstractOverClass = defIsTopLevel)
114
- val owner = ctx.owner.enclosingClass.asClass
115
- val thisTpe = owner.thisType.widen
116
-
117
- var rewrote = false
118
-
119
- // Note: this can be split in two separate transforms(in different groups),
120
- // than first one will collect info about which transformations and rewritings should be applied
121
- // and second one will actually apply,
122
- // now this speculatively transforms tree and throws away result in many cases
123
- val rhsSemiTransformed = {
124
- val transformer = new TailRecElimination (origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
125
- val rhs = atGroupEnd(implicit ctx => transformer.transform(dd.rhs))
126
- rewrote = transformer.rewrote
127
- rhs
128
- }
105
+ cpy.DefDef (dd)(rhs = {
106
+
107
+ val defIsTopLevel = sym.owner.isClass
108
+ val origMeth = sym
109
+ val label = mkLabel(sym, abstractOverClass = defIsTopLevel)
110
+ val owner = ctx.owner.enclosingClass.asClass
111
+ val thisTpe = owner.thisType.widen
112
+
113
+ var rewrote = false
114
+
115
+ // Note: this can be split in two separate transforms(in different groups),
116
+ // than first one will collect info about which transformations and rewritings should be applied
117
+ // and second one will actually apply,
118
+ // now this speculatively transforms tree and throws away result in many cases
119
+ val rhsSemiTransformed = {
120
+ val transformer = new TailRecElimination (origMeth, dd.tparams, owner, thisTpe, mandatory, label, abstractOverClass = defIsTopLevel)
121
+ val rhs = atGroupEnd(implicit ctx => transformer.transform(dd.rhs))
122
+ rewrote = transformer.rewrote
123
+ rhs
124
+ }
129
125
130
- if (rewrote) {
131
- val dummyDefDef = cpy.DefDef (tree)(rhs = rhsSemiTransformed)
132
- if (tree.symbol.owner.isClass) {
133
- val labelDef = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel)
134
- val call = forwarder(label, dd, abstractOverClass = defIsTopLevel, liftThisType = true )
135
- Block (List (labelDef), call)
136
- } else { // inner method. Tail recursion does not change `this`
137
- val labelDef = polyDefDef(label, trefs => vrefss => {
138
- val origMeth = tree.symbol
139
- val origTParams = tree.tparams.map(_.symbol)
140
- val origVParams = tree.vparamss.flatten map (_.symbol)
141
- new TreeTypeMap (
142
- typeMap = identity(_)
143
- .substDealias(origTParams, trefs)
144
- .subst(origVParams, vrefss.flatten.map(_.tpe)),
145
- oldOwners = origMeth :: Nil ,
146
- newOwners = label :: Nil
147
- ).transform(rhsSemiTransformed)
148
- })
149
- val callIntoLabel = (
150
- if (dd.tparams.isEmpty) ref(label)
151
- else ref(label).appliedToTypes(dd.tparams.map(_.tpe))
152
- ).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol))))
153
- Block (List (labelDef), callIntoLabel)
154
- }} else {
155
- if (mandatory) ctx.error(
156
- " TailRec optimisation not applicable, method not tail recursive" ,
157
- // FIXME: want to report this error on `dd.namePos`, but
158
- // because of extension method getting a weird pos, it is
159
- // better to report on symbol so there's no overlap
160
- sym.pos
161
- )
162
- dd.rhs
163
- }
164
- })
165
- }
126
+ if (rewrote) {
127
+ val dummyDefDef = cpy.DefDef (tree)(rhs = rhsSemiTransformed)
128
+ if (tree.symbol.owner.isClass) {
129
+ val labelDef = fullyParameterizedDef(label, dummyDefDef, abstractOverClass = defIsTopLevel)
130
+ val call = forwarder(label, dd, abstractOverClass = defIsTopLevel, liftThisType = true )
131
+ Block (List (labelDef), call)
132
+ } else { // inner method. Tail recursion does not change `this`
133
+ val labelDef = polyDefDef(label, trefs => vrefss => {
134
+ val origMeth = tree.symbol
135
+ val origTParams = tree.tparams.map(_.symbol)
136
+ val origVParams = tree.vparamss.flatten map (_.symbol)
137
+ new TreeTypeMap (
138
+ typeMap = identity(_)
139
+ .substDealias(origTParams, trefs)
140
+ .subst(origVParams, vrefss.flatten.map(_.tpe)),
141
+ oldOwners = origMeth :: Nil ,
142
+ newOwners = label :: Nil
143
+ ).transform(rhsSemiTransformed)
144
+ })
145
+ val callIntoLabel = (
146
+ if (dd.tparams.isEmpty) ref(label)
147
+ else ref(label).appliedToTypes(dd.tparams.map(_.tpe))
148
+ ).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol))))
149
+ Block (List (labelDef), callIntoLabel)
150
+ }} else {
151
+ if (mandatory) ctx.error(
152
+ " TailRec optimisation not applicable, method not tail recursive" ,
153
+ // FIXME: want to report this error on `dd.namePos`, but
154
+ // because of extension method getting a weird pos, it is
155
+ // better to report on symbol so there's no overlap
156
+ sym.pos
157
+ )
158
+ dd.rhs
159
+ }
160
+ })
166
161
case d : DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot ) || methodsWithInnerAnnots.contains(d.symbol) =>
167
162
ctx.error(" TailRec optimisation not applicable, method is neither private nor final so can be overridden" , sym.pos)
168
163
d
@@ -242,8 +237,6 @@ class TailRec extends MiniPhaseTransform with DenotTransformer with FullParamete
242
237
continue
243
238
}
244
239
245
-
246
-
247
240
if (isRecursiveCall) {
248
241
if (ctx.tailPos) {
249
242
val receiverIsSame = enclosingClass.appliedRef.widenDealias =:= recvWiden
0 commit comments