Skip to content

Commit c332e8f

Browse files
Backport "Add a specific error message for local final defs" to LTS (#21155)
Backports #20557 to the LTS branch. PR submitted by the release tooling.
2 parents d120926 + 02fed45 commit c332e8f

File tree

5 files changed

+72
-2
lines changed

5 files changed

+72
-2
lines changed

Diff for: compiler/src/dotty/tools/dotc/parsing/Parsers.scala

+6
Original file line numberDiff line numberDiff line change
@@ -4350,6 +4350,12 @@ object Parsers {
43504350
for (imod <- implicitMods.mods) mods = addMod(mods, imod)
43514351
if (mods.is(Final))
43524352
// A final modifier means the local definition is "class-like". // FIXME: Deal with modifiers separately
4353+
4354+
// See test 17579. We allow `final` on `given` because these can be
4355+
// translated to class definitions, for which `final` is allowed but
4356+
// redundant--there is a seperate warning for this.
4357+
if isDclIntro && in.token != GIVEN then syntaxError(FinalLocalDef())
4358+
43534359
tmplDef(start, mods)
43544360
else
43554361
defOrDcl(start, mods)

Diff for: compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

+2
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
212212
case ContextBoundCompanionNotValueID // errorNumber: 196 - unused in LTS
213213
case InlinedAnonClassWarningID // errorNumber: 197
214214
case UnusedSymbolID // errorNumber: 198
215+
case TailrecNestedCallID //errorNumber: 199 - unused in LTS
216+
case FinalLocalDefID // errorNumber: 200
215217

216218
def errorNumber = ordinal - 1
217219

Diff for: compiler/src/dotty/tools/dotc/reporting/messages.scala

+8-2
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,7 @@ class WrongNumberOfParameters(tree: untpd.Tree, foundCount: Int, pt: Type, expec
18191819

18201820
class DuplicatePrivateProtectedQualifier()(using Context)
18211821
extends SyntaxMsg(DuplicatePrivateProtectedQualifierID) {
1822-
def msg(using Context) = "Duplicate private/protected qualifier"
1822+
def msg(using Context) = "Duplicate private/protected modifier"
18231823
def explain(using Context) =
18241824
i"It is not allowed to combine `private` and `protected` modifiers even if they are qualified to different scopes"
18251825
}
@@ -1828,7 +1828,13 @@ class ExpectedStartOfTopLevelDefinition()(using Context)
18281828
extends SyntaxMsg(ExpectedStartOfTopLevelDefinitionID) {
18291829
def msg(using Context) = "Expected start of definition"
18301830
def explain(using Context) =
1831-
i"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after qualifiers"
1831+
i"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after modifiers"
1832+
}
1833+
1834+
class FinalLocalDef()(using Context)
1835+
extends SyntaxMsg(FinalLocalDefID) {
1836+
def msg(using Context) = i"The ${hl("final")} modifier is not allowed on local definitions"
1837+
def explain(using Context) = ""
18321838
}
18331839

18341840
class NoReturnFromInlineable(owner: Symbol)(using Context)

Diff for: tests/neg/17579.check

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- [E200] Syntax Error: tests/neg/17579.scala:5:10 ---------------------------------------------------------------------
2+
5 | final val v1 = 42 // error: final modifier is not allowed on local definitions
3+
| ^^^
4+
| The final modifier is not allowed on local definitions
5+
-- [E200] Syntax Error: tests/neg/17579.scala:6:15 ---------------------------------------------------------------------
6+
6 | final lazy val v2 = 42 // error: final modifier is not allowed on local definitions
7+
| ^^^
8+
| The final modifier is not allowed on local definitions
9+
-- [E200] Syntax Error: tests/neg/17579.scala:7:10 ---------------------------------------------------------------------
10+
7 | final def v4 = 42 // error: final modifier is not allowed on local definitions
11+
| ^^^
12+
| The final modifier is not allowed on local definitions
13+
-- [E200] Syntax Error: tests/neg/17579.scala:8:10 ---------------------------------------------------------------------
14+
8 | final var v5 = 42 // error: final modifier is not allowed on local definitions
15+
| ^^^
16+
| The final modifier is not allowed on local definitions
17+
-- [E200] Syntax Error: tests/neg/17579.scala:9:10 ---------------------------------------------------------------------
18+
9 | final type Foo = String // error: final modifier is not allowed on local definitions
19+
| ^^^^
20+
| The final modifier is not allowed on local definitions
21+
-- [E088] Syntax Error: tests/neg/17579.scala:14:10 --------------------------------------------------------------------
22+
14 | final private val v3 = 42 // error: expected start of definition
23+
| ^^^^^^^
24+
| Expected start of definition
25+
|
26+
| longer explanation available when compiling with `-explain`
27+
-- [E147] Syntax Warning: tests/neg/17579.scala:19:6 -------------------------------------------------------------------
28+
19 | final given Object with {} // warning: modifier `final` is redundant for this definition
29+
| ^^^^^
30+
| Modifier final is redundant for this definition

Diff for: tests/neg/17579.scala

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class C:
2+
final var v = 42 // ok
3+
4+
def f =
5+
final val v1 = 42 // error: final modifier is not allowed on local definitions
6+
final lazy val v2 = 42 // error: final modifier is not allowed on local definitions
7+
final def v4 = 42 // error: final modifier is not allowed on local definitions
8+
final var v5 = 42 // error: final modifier is not allowed on local definitions
9+
final type Foo = String // error: final modifier is not allowed on local definitions
10+
11+
// We get a different error message here because `private` is also not a
12+
// local modifier token. In the future, we could always parse all tokens and
13+
// then flag those that are not legal at this point.
14+
final private val v3 = 42 // error: expected start of definition
15+
16+
{
17+
// No error in this case, because the `given` is translated to a class
18+
// definition, for which `final` is redundant but not illegal.
19+
final given Object with {} // warning: modifier `final` is redundant for this definition
20+
}
21+
22+
{
23+
// Also no error in this case, because we can't easily distinguish it from
24+
// the previous case.
25+
final given Object = new Object {}
26+
}

0 commit comments

Comments
 (0)