Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make fatal warnings not fail compilation early & aggregate warns #19245

Merged
merged 5 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
runCtx.withProgressCallback: cb =>
_progress = Progress(cb, this, fusedPhases.map(_.traversals).sum)
runPhases(allPhases = fusedPhases)(using runCtx)
ctx.reporter.finalizeReporting()
if (!ctx.reporter.hasErrors)
Rewrites.writeBack()
suppressions.runFinished(hasErrors = ctx.reporter.hasErrors)
Expand Down
13 changes: 6 additions & 7 deletions compiler/src/dotty/tools/dotc/reporting/Reporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,19 +172,14 @@ abstract class Reporter extends interfaces.ReporterResult {
end issueUnconfigured

def issueIfNotSuppressed(dia: Diagnostic)(using Context): Unit =
def toErrorIfFatal(dia: Diagnostic) = dia match
case w: Warning if ctx.settings.silentWarnings.value => dia
case w: ConditionalWarning if w.isSummarizedConditional => dia
case w: Warning if ctx.settings.XfatalWarnings.value => w.toError
case _ => dia

def go() =
import Action.*
dia match
case w: Warning => WConf.parsed.action(dia) match
case Error => issueUnconfigured(w.toError)
case Warning => issueUnconfigured(toErrorIfFatal(w))
case Verbose => issueUnconfigured(toErrorIfFatal(w.setVerbose()))
case Warning => issueUnconfigured(w)
case Verbose => issueUnconfigured(w.setVerbose())
case Info => issueUnconfigured(w.toInfo)
case Silent =>
case _ => issueUnconfigured(dia)
Expand Down Expand Up @@ -214,6 +209,10 @@ abstract class Reporter extends interfaces.ReporterResult {
def incomplete(dia: Diagnostic)(using Context): Unit =
incompleteHandler(dia, ctx)

def finalizeReporting()(using Context) =
if (hasWarnings && ctx.settings.XfatalWarnings.value)
report(new Error("No warnings can be incurred under -Werror (or -Xfatal-warnings)", NoSourcePosition))

/** Summary of warnings and errors */
def summary: String = {
val b = new mutable.ListBuffer[String]
Expand Down
13 changes: 8 additions & 5 deletions compiler/test-resources/repl/rewrite-messages
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
//> using options -source:future-migration -deprecation -Werror
scala> import scala.util._
-- Error: ----------------------------------------------------------------------
-- Migration Warning: ----------------------------------------------------------
1 | import scala.util._
| ^
| `_` is no longer supported for a wildcard import; use `*` instead

No warnings can be incurred under -Werror (or -Xfatal-warnings)
1 warning found
1 error found
scala> extension (x: Int) def foo(y: Int) = x + y
def foo(x: Int)(y: Int): Int

scala> 2 foo 4
-- Error: ----------------------------------------------------------------------
-- Migration Warning: ----------------------------------------------------------
1 | 2 foo 4
| ^^^
|Alphanumeric method foo is not declared infix; it should not be used as infix operator.
|Instead, use method syntax .foo(...) or backticked identifier `foo`.
1 error found
No warnings can be incurred under -Werror (or -Xfatal-warnings)
1 warning found
1 error found
4 changes: 1 addition & 3 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,8 @@ class CompilationTests {
// initialization tests
@Test def checkInitGlobal: Unit = {
implicit val testGroup: TestGroup = TestGroup("checkInitGlobal")
val options = defaultOptions.and("-Ysafe-init-global", "-Xfatal-warnings")
compileFilesInDir("tests/init-global/neg", options, FileFilter.exclude(TestSources.negInitGlobalScala2LibraryTastyBlacklisted)).checkExpectedErrors()
compileFilesInDir("tests/init-global/warn", defaultOptions.and("-Ysafe-init-global"), FileFilter.exclude(TestSources.negInitGlobalScala2LibraryTastyBlacklisted)).checkWarnings()
compileFilesInDir("tests/init-global/pos", options, FileFilter.exclude(TestSources.posInitGlobalScala2LibraryTastyBlacklisted)).checkCompile()
compileFilesInDir("tests/init-global/pos", defaultOptions.and("-Ysafe-init-global", "-Xfatal-warnings"), FileFilter.exclude(TestSources.posInitGlobalScala2LibraryTastyBlacklisted)).checkCompile()
}

// initialization tests
Expand Down
2 changes: 0 additions & 2 deletions tests/init-global/neg/i11262.scala

This file was deleted.

2 changes: 0 additions & 2 deletions tests/init-global/neg/i15883.scala

This file was deleted.

10 changes: 10 additions & 0 deletions tests/init-global/warn/context-sensitivity.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Warning: tests/init-global/warn/context-sensitivity.scala:9:21 ------------------------------------------------------
9 | def foo(): Int = A.m // warn
| ^^^
| Access uninitialized field value m. Calling trace:
| ├── object A: [ context-sensitivity.scala:14 ]
| │ ^
| ├── val m: Int = box1.value.foo() [ context-sensitivity.scala:17 ]
| │ ^^^^^^^^^^^^^^^^
| └── def foo(): Int = A.m // warn [ context-sensitivity.scala:9 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class C(var x: Int) extends Foo {
}

class D(var y: Int) extends Foo {
def foo(): Int = A.m // error
def foo(): Int = A.m // warn
}

class Box(var value: Foo)
Expand All @@ -15,3 +15,4 @@ object A:
val box1: Box = new Box(new C(5))
val box2: Box = new Box(new D(10))
val m: Int = box1.value.foo()

Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
-- Error: tests/init-global/neg/global-cycle1.scala:1:7 ----------------------------------------------------------------
1 |object A { // error
-- Warning: tests/init-global/warn/global-cycle1.scala:1:7 -------------------------------------------------------------
1 |object A { // warn
| ^
| Cyclic initialization: object A -> object B -> object A. Calling trace:
| ├── object A { // error [ global-cycle1.scala:1 ]
| ├── object A { // warn [ global-cycle1.scala:1 ]
| │ ^
| ├── val a: Int = B.b [ global-cycle1.scala:2 ]
| │ ^
| ├── object B { [ global-cycle1.scala:5 ]
| │ ^
| └── val b: Int = A.a // error [ global-cycle1.scala:6 ]
| └── val b: Int = A.a // warn [ global-cycle1.scala:6 ]
| ^
-- Error: tests/init-global/neg/global-cycle1.scala:6:17 ---------------------------------------------------------------
6 | val b: Int = A.a // error
-- Warning: tests/init-global/warn/global-cycle1.scala:6:17 ------------------------------------------------------------
6 | val b: Int = A.a // warn
| ^^^
| Access uninitialized field value a. Calling trace:
| ├── object B { [ global-cycle1.scala:5 ]
| │ ^
| └── val b: Int = A.a // error [ global-cycle1.scala:6 ]
| └── val b: Int = A.a // warn [ global-cycle1.scala:6 ]
| ^^^
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
object A { // error
object A { // warn
val a: Int = B.b
}

object B {
val b: Int = A.a // error
val b: Int = A.a // warn
}

@main
Expand Down
20 changes: 20 additions & 0 deletions tests/init-global/warn/global-cycle14.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Warning: tests/init-global/warn/global-cycle14.scala:8:7 ------------------------------------------------------------
8 |object A { // warn
| ^
| Cyclic initialization: object A -> object B -> object A. Calling trace:
| ├── object A { // warn [ global-cycle14.scala:8 ]
| │ ^
| ├── val n: Int = B.m [ global-cycle14.scala:9 ]
| │ ^
| ├── object B { [ global-cycle14.scala:12 ]
| │ ^
| └── val m: Int = A.n // warn [ global-cycle14.scala:13 ]
| ^
-- Warning: tests/init-global/warn/global-cycle14.scala:13:17 ----------------------------------------------------------
13 | val m: Int = A.n // warn
| ^^^
| Access uninitialized field value n. Calling trace:
| ├── object B { [ global-cycle14.scala:12 ]
| │ ^
| └── val m: Int = A.n // warn [ global-cycle14.scala:13 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ object O {
val d = Data(3)
}

object A { // error
object A { // warn
val n: Int = B.m
}

object B {
val m: Int = A.n // error
val m: Int = A.n // warn
}
10 changes: 10 additions & 0 deletions tests/init-global/warn/global-cycle2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Warning: tests/init-global/warn/global-cycle2.scala:6:21 ------------------------------------------------------------
6 | def foo(): Int = A.a * 2 // warn
| ^^^
| Access uninitialized field value a. Calling trace:
| ├── object A { [ global-cycle2.scala:1 ]
| │ ^
| ├── val a: Int = B.foo() [ global-cycle2.scala:2 ]
| │ ^^^^^^^
| └── def foo(): Int = A.a * 2 // warn [ global-cycle2.scala:6 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ object A {
}

object B {
def foo(): Int = A.a * 2 // error
def foo(): Int = A.a * 2 // warn
}
10 changes: 10 additions & 0 deletions tests/init-global/warn/global-cycle3.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Warning: tests/init-global/warn/global-cycle3.scala:2:21 ------------------------------------------------------------
2 | def foo(): Int = B.a + 10 // warn
| ^^^
| Access uninitialized field value a. Calling trace:
| ├── object B { [ global-cycle3.scala:5 ]
| │ ^
| ├── val a: Int = A(4).foo() [ global-cycle3.scala:6 ]
| │ ^^^^^^^^^^
| └── def foo(): Int = B.a + 10 // warn [ global-cycle3.scala:2 ]
| ^^^
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class A(x: Int) {
def foo(): Int = B.a + 10 // error
def foo(): Int = B.a + 10 // warn
}

object B {
Expand Down
10 changes: 10 additions & 0 deletions tests/init-global/warn/global-cycle4.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Warning: tests/init-global/warn/global-cycle4.scala:10:21 -----------------------------------------------------------
10 | def foo(): Int = O.a + 10 // warn
| ^^^
| Access uninitialized field value a. Calling trace:
| ├── object O { [ global-cycle4.scala:17 ]
| │ ^
| ├── val a: Int = D(5).bar().foo() [ global-cycle4.scala:18 ]
| │ ^^^^^^^^^^^^^^^^
| └── def foo(): Int = O.a + 10 // warn [ global-cycle4.scala:10 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class B extends A {
}

class C extends A {
def foo(): Int = O.a + 10 // error
def foo(): Int = O.a + 10 // warn
}

class D(x: Int) {
Expand Down
9 changes: 9 additions & 0 deletions tests/init-global/warn/global-cycle5.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Warning: tests/init-global/warn/global-cycle5.scala:10:17 -----------------------------------------------------------
10 | val b: Int = A.a.foo() // warn
| ^^^
|Reading mutable state of object A during initialization of object B.
|Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. Calling trace:
|├── object B { [ global-cycle5.scala:9 ]
|│ ^
|└── val b: Int = A.a.foo() // warn [ global-cycle5.scala:10 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object A {
}

object B {
val b: Int = A.a.foo() // error
val b: Int = A.a.foo() // warn
}

class Y extends X {
Expand Down
28 changes: 28 additions & 0 deletions tests/init-global/warn/global-cycle6.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- Warning: tests/init-global/warn/global-cycle6.scala:1:7 -------------------------------------------------------------
1 |object A { // warn
| ^
| Cyclic initialization: object A -> object B -> object A. Calling trace:
| ├── object A { // warn [ global-cycle6.scala:1 ]
| │ ^
| ├── val n: Int = B.m [ global-cycle6.scala:2 ]
| │ ^
| ├── object B { [ global-cycle6.scala:8 ]
| │ ^
| ├── val a = new A.Inner [ global-cycle6.scala:9 ]
| │ ^^^^^^^^^^^
| ├── class Inner { [ global-cycle6.scala:3 ]
| │ ^
| └── println(n) // warn [ global-cycle6.scala:4 ]
| ^
-- Warning: tests/init-global/warn/global-cycle6.scala:4:12 ------------------------------------------------------------
4 | println(n) // warn
| ^
| Access uninitialized field value n. Calling trace:
| ├── object B { [ global-cycle6.scala:8 ]
| │ ^
| ├── val a = new A.Inner [ global-cycle6.scala:9 ]
| │ ^^^^^^^^^^^
| ├── class Inner { [ global-cycle6.scala:3 ]
| │ ^
| └── println(n) // warn [ global-cycle6.scala:4 ]
| ^
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
object A { // error
object A { // warn
val n: Int = B.m
class Inner {
println(n) // error
println(n) // warn
}
}

Expand Down
20 changes: 20 additions & 0 deletions tests/init-global/warn/global-cycle7.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Warning: tests/init-global/warn/global-cycle7.scala:1:7 -------------------------------------------------------------
1 |object A { // warn
| ^
| Cyclic initialization: object A -> object B -> object A. Calling trace:
| ├── object A { // warn [ global-cycle7.scala:1 ]
| │ ^
| ├── val n: Int = B.m [ global-cycle7.scala:2 ]
| │ ^
| ├── object B { [ global-cycle7.scala:5 ]
| │ ^
| └── val m: Int = A.n // warn [ global-cycle7.scala:6 ]
| ^
-- Warning: tests/init-global/warn/global-cycle7.scala:6:17 ------------------------------------------------------------
6 | val m: Int = A.n // warn
| ^^^
| Access uninitialized field value n. Calling trace:
| ├── object B { [ global-cycle7.scala:5 ]
| │ ^
| └── val m: Int = A.n // warn [ global-cycle7.scala:6 ]
| ^^^
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
object A { // error
object A { // warn
val n: Int = B.m
}

object B {
val m: Int = A.n // error
val m: Int = A.n // warn
}

abstract class TokensCommon {
Expand Down
16 changes: 16 additions & 0 deletions tests/init-global/warn/global-cycle8.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Warning: tests/init-global/warn/global-cycle8.scala:9:7 -------------------------------------------------------------
9 |object O { // warn
| ^
| Cyclic initialization: object O -> object P -> object O. Calling trace:
| ├── object O { // warn [ global-cycle8.scala:9 ]
| │ ^
| ├── println(P.m) [ global-cycle8.scala:11 ]
| │ ^
| ├── object P { [ global-cycle8.scala:14 ]
| │ ^
| ├── val m = Q.bar(new B) [ global-cycle8.scala:15 ]
| │ ^^^^^^^^^^^^
| ├── def bar(b: B) = b.a.foo() [ global-cycle8.scala:19 ]
| │ ^^^^^^^^^
| └── def foo() = println(O.n) [ global-cycle8.scala:2 ]
| ^
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class B {
val a = new A
}

object O { // error
object O { // warn
val n: Int = 10
println(P.m)
}
Expand Down
9 changes: 9 additions & 0 deletions tests/init-global/warn/global-irrelevance1.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Warning: tests/init-global/warn/global-irrelevance1.scala:5:12 ------------------------------------------------------
5 | var y = A.x * 2 // warn
| ^^^
|Reading mutable state of object A during initialization of object B.
|Reading mutable state of other static objects is forbidden as it breaks initialization-time irrelevance. Calling trace:
|├── object B: [ global-irrelevance1.scala:4 ]
|│ ^
|└── var y = A.x * 2 // warn [ global-irrelevance1.scala:5 ]
| ^^^
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ object A:
var x = 6

object B:
var y = A.x * 2 // error
var y = A.x * 2 // warn
13 changes: 13 additions & 0 deletions tests/init-global/warn/global-irrelevance2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Warning: tests/init-global/warn/global-irrelevance2.scala:5:6 -------------------------------------------------------
5 | A.x = b * 2 // warn
| ^^^^^^^^^^^^
| Mutating object A during initialization of object B.
| Mutating other static objects during the initialization of one static object is forbidden. Calling trace:
| ├── object B: [ global-irrelevance2.scala:7 ]
| │ ^
| ├── new B(10) [ global-irrelevance2.scala:8 ]
| │ ^^^^^^^^^
| ├── class B(b: Int): [ global-irrelevance2.scala:4 ]
| │ ^
| └── A.x = b * 2 // warn [ global-irrelevance2.scala:5 ]
| ^^^^^^^^^^^^
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ object A:
var x = 6

class B(b: Int):
A.x = b * 2 // error
A.x = b * 2 // warn

object B:
new B(10)
Loading
Loading