Skip to content

Commit 24fb64a

Browse files
Merge pull request #5616 from youroff/master
Better error for StaticFieldShouldPrecedeNonStatic rule
2 parents 0caf45e + 376766f commit 24fb64a

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ public enum ErrorMessageID {
142142
StaticOverridingNonStaticMembersID,
143143
OverloadInRefinementID,
144144
NoMatchingOverloadID,
145-
StableIdentPatternID
145+
StableIdentPatternID,
146+
StaticFieldsShouldPrecedeNonStaticID
146147
;
147148

148149
public int errorNumber() {

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

+22
Original file line numberDiff line numberDiff line change
@@ -1936,6 +1936,28 @@ object messages {
19361936
hl"${"@static"} members are only allowed inside objects."
19371937
}
19381938

1939+
case class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends Message(StaticFieldsShouldPrecedeNonStaticID) {
1940+
val msg: String = hl"${"@static"} $member in ${member.owner} must be defined before non-static fields."
1941+
val kind: String = "Syntax"
1942+
1943+
val explanation: String = {
1944+
val nonStatics = defns.takeWhile(_.symbol != member).take(3).filter(_.isInstanceOf[tpd.ValDef])
1945+
val codeExample = s"""object ${member.owner.name.firstPart} {
1946+
| @static ${member} = ...
1947+
| ${nonStatics.map(m => s"${m.symbol} = ...").mkString("\n ")}
1948+
| ...
1949+
|}"""
1950+
hl"""The fields annotated with @static should precede any non @static fields.
1951+
|This ensures that we do not introduce surprises for users in initialization order of this class.
1952+
|Static field are initialized when class loading the code of Foo.
1953+
|Non static fields are only initialized the first time that Foo is accessed.
1954+
|
1955+
|The definition of ${member.name} should have been before the non ${"@static val"}s:
1956+
|$codeExample
1957+
|"""
1958+
}
1959+
}
1960+
19391961
case class CyclicInheritance(symbol: Symbol, addendum: String)(implicit ctx: Context) extends Message(CyclicInheritanceID) {
19401962
val kind: String = "Syntax"
19411963
val msg: String = hl"Cyclic inheritance: $symbol extends itself$addendum"

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class CheckStatic extends MiniPhase {
3737
}
3838

3939
if (defn.isInstanceOf[ValDef] && hadNonStaticField) {
40-
ctx.error("@static fields should precede non-static ones", defn.pos)
40+
ctx.error(StaticFieldsShouldPrecedeNonStatic(defn.symbol, defns), defn.pos)
4141
}
4242

4343
val companion = ctx.owner.companionClass

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

+15
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,21 @@ class ErrorMessagesTests extends ErrorMessagesTest {
13931393
assertEquals(field.show, "method bar")
13941394
}
13951395

1396+
@Test def staticShouldPrecedeNonStatic =
1397+
checkMessagesAfter(CheckStatic.name) {
1398+
"""
1399+
|class Foo
1400+
|object Foo {
1401+
| val foo = 1
1402+
| @annotation.static val bar = 2
1403+
|}
1404+
""".stripMargin
1405+
}.expect { (ictx, messages) =>
1406+
implicit val ctx: Context = ictx
1407+
val StaticFieldsShouldPrecedeNonStatic(field, _) = messages.head
1408+
assertEquals(field.show, "value bar")
1409+
}
1410+
13961411
@Test def cyclicInheritance =
13971412
checkMessagesAfter(FrontEnd.name) {
13981413
"class A extends A"

0 commit comments

Comments
 (0)