@@ -208,6 +208,7 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
208208 companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~ OVERRIDE & ~ PROTECTED | FINAL )
209209 setAnnotations origMeth.annotations
210210 )
211+ origMeth.removeAnnotation(TailrecClass ) // it's on the extension method, now.
211212 companion.info.decls.enter(extensionMeth)
212213 }
213214
@@ -221,15 +222,16 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
221222 val extensionParams = allParameters(extensionMono)
222223 val extensionThis = gen.mkAttributedStableRef(thiz setPos extensionMeth.pos)
223224
224- val extensionBody = (
225- rhs
225+ val extensionBody : Tree = {
226+ val tree = rhs
226227 .substituteSymbols(origTpeParams, extensionTpeParams)
227228 .substituteSymbols(origParams, extensionParams)
228229 .substituteThis(origThis, extensionThis)
229230 .changeOwner(origMeth -> extensionMeth)
230- )
231+ new SubstututeRecursion (origMeth, extensionMeth, unit).transform(tree)
232+ }
231233
232- // Record the extension method ( FIXME: because... ? )
234+ // Record the extension method. Later, in `Extender#transformStats`, these will be added to the companion object.
233235 extensionDefs(companion) += atPos(tree.pos)(DefDef (extensionMeth, extensionBody))
234236
235237 // These three lines are assembling Foo.bar$extension[T1, T2, ...]($this)
@@ -264,4 +266,33 @@ abstract class ExtensionMethods extends Transform with TypingTransformers {
264266 stat
265267 }
266268 }
269+
270+ final class SubstututeRecursion (origMeth : Symbol , extensionMeth : Symbol ,
271+ unit : CompilationUnit ) extends TypingTransformer (unit) {
272+ override def transform (tree : Tree ): Tree = tree match {
273+ // SI-6574 Rewrite recursive calls against the extension method so they can
274+ // be tail call optimized later. The tailcalls phases comes before
275+ // erasure, which performs this translation more generally at all call
276+ // sites.
277+ //
278+ // // Source
279+ // class C[C] { def meth[M](a: A) = { { <expr>: C[C'] }.meth[M'] } }
280+ //
281+ // // Translation
282+ // class C[C] { def meth[M](a: A) = { { <expr>: C[C'] }.meth[M'](a1) } }
283+ // object C { def meth$extension[M, C](this$: C[C], a: A)
284+ // = { meth$extension[M', C']({ <expr>: C[C'] })(a1) } }
285+ case treeInfo.Applied (sel @ Select (qual, _), targs, argss) if sel.symbol == origMeth =>
286+ import gen .CODE ._
287+ localTyper.typedPos(tree.pos) {
288+ val allArgss = List (qual) :: argss
289+ val origThis = extensionMeth.owner.companionClass
290+ val baseType = qual.tpe.baseType(origThis)
291+ val allTargs = targs.map(_.tpe) ::: baseType.typeArgs
292+ val fun = gen.mkAttributedTypeApply(THIS (extensionMeth.owner), extensionMeth, allTargs)
293+ allArgss.foldLeft(fun)(Apply (_, _))
294+ }
295+ case _ => super .transform(tree)
296+ }
297+ }
267298}
0 commit comments