Skip to content

Commit 9648c63

Browse files
committed
Fix wrong treatment of Super nodes in TailRec
1 parent e501845 commit 9648c63

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

compiler/src/dotty/tools/dotc/transform/TailRec.scala

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,16 @@ package transform
33

44
import ast.{TreeTypeMap, tpd}
55
import config.Printers.tailrec
6-
import core.Contexts._
7-
import core.Constants.Constant
8-
import core.Flags._
9-
import core.NameKinds.{TailLabelName, TailLocalName, TailTempName}
10-
import core.StdNames.nme
11-
import core.Symbols._
12-
import reporting._
6+
import core.*
7+
import Contexts.*, Flags.*, Symbols.*
8+
import Constants.Constant
9+
import NameKinds.{TailLabelName, TailLocalName, TailTempName}
10+
import StdNames.nme
11+
import reporting.*
1312
import transform.MegaPhase.MiniPhase
1413
import util.LinearSet
1514
import dotty.tools.uncheckedNN
1615

17-
1816
/** A Tail Rec Transformer.
1917
*
2018
* What it does:
@@ -161,15 +159,26 @@ class TailRec extends MiniPhase {
161159
val rhsFullyTransformed = varForRewrittenThis match {
162160
case Some(localThisSym) =>
163161
val thisRef = localThisSym.termRef
164-
new TreeTypeMap(
162+
val substitute = new TreeTypeMap(
165163
typeMap = _.substThisUnlessStatic(enclosingClass, thisRef)
166164
.subst(rewrittenParamSyms, varsForRewrittenParamSyms.map(_.termRef)),
167165
treeMap = {
168166
case tree: This if tree.symbol == enclosingClass => Ident(thisRef)
169167
case tree => tree
170168
}
171-
).transform(rhsSemiTransformed)
172-
169+
)
170+
// The previous map will map `This` references to `Ident`s even under `Super`.
171+
// This violates super's contract. We fix this by cleaning up `Ident`s under
172+
// super, mapping them back to the original `This` reference. This is not
173+
// very elegant, but I did not manage to find a cleaner way to handle this.
174+
// See pos/tailrec-super.scala for a test case.
175+
val cleanup = new TreeMap:
176+
override def transform(t: Tree)(using Context) = t match
177+
case Super(qual: Ident, mix) if !qual.tpe.isInstanceOf[Types.ThisType] =>
178+
cpy.Super(t)(This(enclosingClass), mix)
179+
case _ =>
180+
super.transform(t)
181+
cleanup.transform(substitute.transform(rhsSemiTransformed))
173182
case none =>
174183
new TreeTypeMap(
175184
typeMap = _.subst(rewrittenParamSyms, varsForRewrittenParamSyms.map(_.termRef))

tests/pos/tailrec-super.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Tree
2+
case class Inlined(call: Tree, bindings: List[String], expr: Tree) extends Tree
3+
case object EmptyTree extends Tree
4+
class Context
5+
6+
class Transform:
7+
def transform(tree: Tree)(using Context): Tree = tree
8+
9+
class Inliner:
10+
var enclosingInlineds: List[String] = Nil
11+
private def expandMacro(using Context) =
12+
val inlinedNormalizer = new Transform:
13+
override def transform(tree: Tree)(using Context) = tree match
14+
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
15+
case _ => super.transform(tree)
16+
17+
object Inliner

0 commit comments

Comments
 (0)