Skip to content

Commit 9015f02

Browse files
committed
Run ExtensionMethods after TailRec
1 parent bf62402 commit 9015f02

File tree

4 files changed

+21
-12
lines changed

4 files changed

+21
-12
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ class Compiler {
6565
List(new CheckStatic, // Check restrictions that apply to @static members
6666
new ElimRepeated, // Rewrite vararg parameters and arguments
6767
new NormalizeFlags, // Rewrite some definition flags
68-
new ExtensionMethods, // Expand methods of value classes with extension methods
6968
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
7069
new ShortcutImplicits, // Allow implicit functions without creating closures
7170
new TailRec, // Rewrite tail recursion to loops
71+
new ExtensionMethods, // Expand methods of value classes with extension methods
7272
new ByNameClosures, // Expand arguments to by-name parameters to closures
7373
new LiftTry, // Put try expressions that might execute on non-empty stacks into their own methods
7474
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope

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

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import SymUtils._
3434
* This is different from the implementation of value classes in Scala 2
3535
* (see SIP-15) which uses `asInstanceOf` which does not typecheck.
3636
*
37-
* Finally, if the constructor of a value class is private pr protected
37+
* Finally, if the constructor of a value class is private or protected
3838
* it is widened to public.
3939
*/
4040
class ExtensionMethods extends MiniPhase with DenotTransformer with FullParameterization { thisPhase =>
@@ -47,6 +47,7 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete
4747

4848
override def runsAfter = Set(
4949
ElimRepeated.name,
50+
TailRec.name, // if ran before, tailrec reports spurious errors (original method is not tailrec anymore)
5051
ProtectedAccessors.name // protected accessors cannot handle code that is moved from class to companion object
5152
)
5253

@@ -111,12 +112,7 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete
111112
moduleClassSym
112113
}
113114
case ref: SymDenotation =>
114-
if (isMethodWithExtension(ref.symbol) && ref.hasAnnotation(defn.TailrecAnnot)) {
115-
val ref1 = ref.copySymDenotation()
116-
ref1.removeAnnotation(defn.TailrecAnnot)
117-
ref1
118-
}
119-
else if (ref.isConstructor && isDerivedValueClass(ref.owner) && ref.is(AccessFlags)) {
115+
if (ref.isConstructor && isDerivedValueClass(ref.owner) && ref.is(AccessFlags)) {
120116
val ref1 = ref.copySymDenotation()
121117
ref1.resetFlag(AccessFlags)
122118
ref1
@@ -137,8 +133,7 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete
137133
(imeth.flags | Final) &~ (Override | Protected | AbsOverride),
138134
fullyParameterizedType(imeth.info, imeth.owner.asClass),
139135
privateWithin = imeth.privateWithin, coord = imeth.coord)
140-
extensionMeth.addAnnotations(imeth.annotations)(ctx.withPhase(thisPhase))
141-
// need to change phase to add tailrec annotation which gets removed from original method in the same phase.
136+
extensionMeth.addAnnotations(imeth.annotations)
142137
extensionMeth
143138
}
144139

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ class TailRec extends MiniPhase with FullParameterization {
6868

6969
override def phaseName: String = TailRec.name
7070

71-
override def runsAfter = Set(ShortcutImplicits.name) // Replaces non-tail calls by tail calls
71+
override def runsAfter = Set(
72+
ShortcutImplicits.name // Replaces non-tail calls by tail calls
73+
)
7274

7375
final val labelFlags = Flags.Synthetic | Flags.Label
7476

@@ -144,7 +146,8 @@ class TailRec extends MiniPhase with FullParameterization {
144146
else ref(label).appliedToTypes(dd.tparams.map(_.tpe))
145147
).appliedToArgss(vparamss0.map(_.map(x=> ref(x.symbol))))
146148
Block(List(labelDef), callIntoLabel)
147-
}} else {
149+
}
150+
} else {
148151
if (mandatory) ctx.error(
149152
"TailRec optimisation not applicable, method not tail recursive",
150153
// FIXME: want to report this error on `dd.namePos`, but

tests/run/value-classes-tailrec.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class VCInt(val v: Int) extends AnyVal {
2+
@annotation.tailrec final def tailCall: Boolean =
3+
if (v > 0) new VCInt(v - 1).tailCall
4+
else true
5+
}
6+
7+
object Test {
8+
def main(args: Array[String]): Unit = {
9+
assert(new VCInt(10).tailCall)
10+
}
11+
}

0 commit comments

Comments
 (0)