Skip to content

Commit 1263551

Browse files
committed
improve error message for @tailrec
Now the compiler will give compile errors if the annotation is used on other kinds then methods.
1 parent 64929b4 commit 1263551

File tree

5 files changed

+39
-17
lines changed

5 files changed

+39
-17
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,10 +1825,15 @@ object messages {
18251825
}
18261826
}
18271827

1828-
case class TailrecNotApplicable(method: Symbol)(implicit ctx: Context)
1828+
case class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context)
18291829
extends Message(TailrecNotApplicableID) {
18301830
val kind = "Syntax"
1831-
val msg = hl"TailRec optimisation not applicable, $method is neither ${"private"} nor ${"final"}."
1831+
val symbolKind = symbol.showKind
1832+
val msg =
1833+
if (symbol.is(Method))
1834+
hl"TailRec optimisation not applicable, $symbol is neither ${"private"} nor ${"final"}."
1835+
else
1836+
hl"TailRec optimisation not applicable, ${symbolKind} isn't a method."
18321837
val explanation =
18331838
hl"A method annotated ${"@tailrec"} must be declared ${"private"} or ${"final"} so it can't be overridden."
18341839
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import ast.{TreeTypeMap, tpd}
66
import core._
77
import Contexts.Context
88
import Decorators._
9-
import DenotTransformers.IdentityDenotTransformer
10-
import Denotations.SingleDenotation
119
import Symbols._
1210
import Types._
1311
import NameKinds.TailLabelName
@@ -161,9 +159,6 @@ class TailRec extends MiniPhase with FullParameterization {
161159
case d: DefDef if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) =>
162160
ctx.error(TailrecNotApplicable(sym), sym.pos)
163161
d
164-
case d if d.symbol.hasAnnotation(defn.TailrecAnnot) || methodsWithInnerAnnots.contains(d.symbol) =>
165-
ctx.error("TailRec optimisation not applicable, not a method", sym.pos)
166-
d
167162
case _ => tree
168163
}
169164

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,25 @@ import ast._
77
import Contexts._
88
import Types._
99
import Flags._
10-
import Denotations._
1110
import Names._
1211
import StdNames._
13-
import NameOps._
1412
import Symbols._
1513
import Trees._
1614
import TreeInfo._
1715
import ProtoTypes._
18-
import Constants._
19-
import Scopes._
2016
import CheckRealizable._
2117
import ErrorReporting.errorTree
2218

23-
import annotation.unchecked
2419
import util.Positions._
25-
import util.Stats
26-
import util.common._
2720
import transform.SymUtils._
2821
import Decorators._
29-
import Uniques._
3022
import ErrorReporting.{err, errorType}
3123
import config.Printers.typr
3224
import NameKinds.DefaultGetterName
3325

3426
import collection.mutable
3527
import SymDenotations.{NoCompleter, NoDenotation}
36-
import dotty.tools.dotc.reporting.diagnostic.{ErrorMessageID, Message}
28+
import dotty.tools.dotc.reporting.diagnostic.Message
3729
import dotty.tools.dotc.reporting.diagnostic.messages._
3830
import dotty.tools.dotc.transform.ValueClasses._
3931

@@ -358,6 +350,9 @@ object Checking {
358350
fail(AbstractOverrideOnlyInTraits(sym))
359351
if (sym.is(Trait) && sym.is(Final))
360352
fail(TraitsMayNotBeFinal(sym))
353+
// Skip ModuleVal since the annotation will also be on the ModuleClass
354+
if (sym.hasAnnotation(defn.TailrecAnnot) && !sym.is(Method | ModuleVal))
355+
fail(TailrecNotApplicable(sym))
361356
if (sym.hasAnnotation(defn.NativeAnnot)) {
362357
if (!sym.is(Deferred))
363358
fail(NativeMembersMayNotHaveImplementation(sym))

compiler/src/dotty/tools/dotc/typer/FrontEnd.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ast.Trees._
1515

1616
class FrontEnd extends Phase {
1717

18-
override def phaseName = "frontend"
18+
override def phaseName = FrontEnd.name
1919
override def isTyper = true
2020
import ast.tpd
2121

@@ -103,3 +103,7 @@ class FrontEnd extends Phase {
103103
typeCheck
104104
}
105105
}
106+
107+
object FrontEnd {
108+
val name = "frontend"
109+
}

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import dotty.tools.dotc.core.Types.WildcardType
77
import dotty.tools.dotc.parsing.Tokens
88
import dotty.tools.dotc.reporting.diagnostic.messages._
99
import dotty.tools.dotc.transform.PostTyper
10+
import dotty.tools.dotc.typer.FrontEnd
1011
import org.junit.Assert._
1112
import org.junit.Test
1213

@@ -1361,4 +1362,26 @@ class ErrorMessagesTests extends ErrorMessagesTest {
13611362
val (msg @ ImportRenamedTwice(ident)) :: Nil = messages
13621363
assertEquals(ident.show, "Integer")
13631364
}
1365+
1366+
@Test def tailRecOptimisation =
1367+
checkMessagesAfter(FrontEnd.name) {
1368+
"""
1369+
|import scala.annotation.tailrec
1370+
|@tailrec
1371+
|object Test {
1372+
| @tailrec val a = ""
1373+
| @tailrec var b = ""
1374+
|}
1375+
|@tailrec
1376+
|class Test {}
1377+
|
1378+
""".stripMargin
1379+
}.expect{ (ictx, messages) =>
1380+
implicit val ctx: Context = ictx
1381+
assertMessageCount(4, messages)
1382+
1383+
val tailRegMessages = messages.map{ case m :TailrecNotApplicable => m.symbolKind}.toSet
1384+
assertEquals(tailRegMessages, Set("variable", "value", "object", "class"))
1385+
}
1386+
13641387
}

0 commit comments

Comments
 (0)