Skip to content

Commit 13250bc

Browse files
authored
Merge pull request #13266 from dwijnand/repl-diagnostic-print
2 parents d8cf8a3 + 8f226e5 commit 13250bc

29 files changed

+183
-96
lines changed

compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,19 @@ trait MessageRendering {
107107
.mkString(EOL)
108108
}
109109

110+
/** The source file path, line and column numbers from the given SourcePosition */
111+
def posFileStr(pos: SourcePosition): String =
112+
val path = pos.source.file.path
113+
if pos.exists then s"$path:${pos.line + 1}:${pos.column}" else path
114+
110115
/** The separator between errors containing the source file and error type
111116
*
112117
* @return separator containing error location and kind
113118
*/
114119
def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(using Context): String =
115120
if (pos.source != NoSourcePosition.source) hl(diagnosticLevel)({
116-
val pos1 = pos.nonInlined
117-
val file = if !pos.exists then pos1.source.file.toString else
118-
s"${pos1.source.file.toString}:${pos1.line + 1}:${pos1.column}"
121+
val fileAndPos = posFileStr(pos.nonInlined)
122+
val file = if fileAndPos.isEmpty || fileAndPos.endsWith(" ") then fileAndPos else s"$fileAndPos "
119123
val errId =
120124
if (message.errorId ne ErrorMessageID.NoExplanationID) {
121125
val errorNumber = message.errorId.errorNumber
@@ -124,7 +128,7 @@ trait MessageRendering {
124128
val kind =
125129
if (message.kind == "") diagnosticLevel
126130
else s"${message.kind} $diagnosticLevel"
127-
val prefix = s"-- ${errId}${kind}: $file "
131+
val prefix = s"-- ${errId}${kind}: $file"
128132

129133
prefix +
130134
("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0))
@@ -192,12 +196,13 @@ trait MessageRendering {
192196

193197
def diagnosticLevel(dia: Diagnostic): String =
194198
dia match {
195-
case dia: Error => "Error"
196199
case dia: FeatureWarning => "Feature Warning"
197200
case dia: DeprecationWarning => "Deprecation Warning"
198201
case dia: UncheckedWarning => "Unchecked Warning"
199202
case dia: MigrationWarning => "Migration Warning"
200-
case dia: Warning => "Warning"
201-
case dia: Info => "Info"
203+
case _ => dia.level match // Diagnostic isn't sealed (e.g. created in the REPL) so provide a fallback
204+
case interfaces.Diagnostic.ERROR => "Error"
205+
case interfaces.Diagnostic.WARNING => "Warning"
206+
case interfaces.Diagnostic.INFO => "Info"
202207
}
203208
}

compiler/src/dotty/tools/repl/Rendering.scala

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,6 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
3131

3232
private val MaxStringElements: Int = 1000 // no need to mkString billions of elements
3333

34-
/** A `MessageRenderer` for the REPL without file positions */
35-
private val messageRenderer = new MessageRendering {
36-
override def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(using Context): String =
37-
hl(diagnosticLevel)(s"-- $diagnosticLevel:")
38-
}
39-
4034
private var myClassLoader: ClassLoader = _
4135

4236
private var myReplStringOf: Object => String = _
@@ -126,14 +120,6 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {
126120
}
127121
}
128122

129-
/** Formats errors using the `messageRenderer` */
130-
def formatError(dia: Diagnostic)(implicit state: State): Diagnostic =
131-
new Diagnostic(
132-
messageRenderer.messageAndPos(dia)(using state.context),
133-
dia.pos,
134-
dia.level
135-
)
136-
137123
def renderTypeDef(d: Denotation)(using Context): Diagnostic =
138124
infoDiagnostic("// defined " ++ d.symbol.showUser, d)
139125

compiler/src/dotty/tools/repl/ReplCompiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class ReplCompiler extends Compiler {
153153
private def runCompilationUnit(unit: CompilationUnit, state: State): Result[(CompilationUnit, State)] = {
154154
val ctx = state.context
155155
ctx.run.compileUnits(unit :: Nil)
156+
ctx.run.printSummary() // this outputs "2 errors found" like normal - but we might decide that's needlessly noisy for the REPL
156157

157158
if (!ctx.reporter.hasErrors) (unit, state).result
158159
else ctx.reporter.removeBufferedMessages(using ctx).errors

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dotty.tools.repl
22

3-
import java.io.{File => JFile, PrintStream}
3+
import java.io.{File => JFile, PrintStream, PrintWriter}
44
import java.nio.charset.StandardCharsets
55

66
import dotty.tools.dotc.ast.Trees._
@@ -17,9 +17,10 @@ import dotty.tools.dotc.core.NameOps._
1717
import dotty.tools.dotc.core.Names.Name
1818
import dotty.tools.dotc.core.StdNames._
1919
import dotty.tools.dotc.core.Symbols.{Symbol, defn}
20+
import dotty.tools.dotc.interfaces
2021
import dotty.tools.dotc.interactive.Completion
2122
import dotty.tools.dotc.printing.SyntaxHighlighting
22-
import dotty.tools.dotc.reporting.{MessageRendering, StoreReporter}
23+
import dotty.tools.dotc.reporting.{ConsoleReporter, MessageRendering, StoreReporter}
2324
import dotty.tools.dotc.reporting.{Message, Diagnostic}
2425
import dotty.tools.dotc.util.Spans.Span
2526
import dotty.tools.dotc.util.{SourceFile, SourcePosition}
@@ -261,7 +262,6 @@ class ReplDriver(settings: Array[String],
261262

262263
val warnings = newState.context.reporter
263264
.removeBufferedMessages(using newState.context)
264-
.map(rendering.formatError)
265265

266266
inContext(newState.context) {
267267
val (updatedState, definitions) =
@@ -278,8 +278,7 @@ class ReplDriver(settings: Array[String],
278278

279279
(definitions ++ warnings)
280280
.sorted
281-
.map(_.msg)
282-
.foreach(out.println)
281+
.foreach(printDiagnostic)
283282

284283
updatedState
285284
}
@@ -422,7 +421,20 @@ class ReplDriver(settings: Array[String],
422421

423422
/** shows all errors nicely formatted */
424423
private def displayErrors(errs: Seq[Diagnostic])(implicit state: State): State = {
425-
errs.map(rendering.formatError).map(_.msg).foreach(out.println)
424+
errs.foreach(printDiagnostic)
426425
state
427426
}
427+
428+
/** Like ConsoleReporter, but without file paths or real -Xprompt'ing */
429+
private object ReplConsoleReporter extends ConsoleReporter(
430+
reader = null, // this short-circuits the -Xprompt display from waiting for an input
431+
writer = new PrintWriter(out, /* autoFlush = */ true), // write to out, not Console.err
432+
) {
433+
override def posFileStr(pos: SourcePosition) = "" // omit file paths
434+
}
435+
436+
/** Print warnings & errors using ReplConsoleReporter, and info straight to out */
437+
private def printDiagnostic(dia: Diagnostic)(implicit state: State) = dia.level match
438+
case interfaces.Diagnostic.INFO => out.println(dia.msg) // print REPL's special info diagnostics directly to out
439+
case _ => ReplConsoleReporter.doReport(dia)(using state.context)
428440
}

compiler/test-resources/repl/1379

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
scala> object Foo { val bar = new Object { def baz = 1 }; bar.baz }
2-
-- Error:
2+
-- [E008] Not Found Error: -----------------------------------------------------
33
1 | object Foo { val bar = new Object { def baz = 1 }; bar.baz }
44
| ^^^^^^^
5-
| value baz is not a member of Object
5+
| value baz is not a member of Object
6+
1 error found

compiler/test-resources/repl/errmsgs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,110 @@
11
scala> class Inv[T](x: T)
22
// defined class Inv
33
scala> val x: List[String] = List(1)
4-
-- Error:
4+
-- [E007] Type Mismatch Error: -------------------------------------------------
55
1 | val x: List[String] = List(1)
66
| ^
77
| Found: (1 : Int)
88
| Required: String
9+
longer explanation available when compiling with `-explain`
10+
1 error found
911
scala> val y: List[List[String]] = List(List(1))
10-
-- Error:
12+
-- [E007] Type Mismatch Error: -------------------------------------------------
1113
1 | val y: List[List[String]] = List(List(1))
1214
| ^
1315
| Found: (1 : Int)
1416
| Required: String
17+
longer explanation available when compiling with `-explain`
18+
1 error found
1519
scala> val z: (List[String], List[Int]) = (List(1), List("a"))
16-
-- Error:
20+
-- [E007] Type Mismatch Error: -------------------------------------------------
1721
1 | val z: (List[String], List[Int]) = (List(1), List("a"))
1822
| ^
1923
| Found: (1 : Int)
2024
| Required: String
21-
-- Error:
25+
longer explanation available when compiling with `-explain`
26+
-- [E007] Type Mismatch Error: -------------------------------------------------
2227
1 | val z: (List[String], List[Int]) = (List(1), List("a"))
2328
| ^^^
2429
| Found: ("a" : String)
2530
| Required: Int
31+
longer explanation available when compiling with `-explain`
32+
2 errors found
2633
scala> val a: Inv[String] = new Inv(new Inv(1))
27-
-- Error:
34+
-- [E007] Type Mismatch Error: -------------------------------------------------
2835
1 | val a: Inv[String] = new Inv(new Inv(1))
2936
| ^^^^^^^^^^
3037
| Found: Inv[Int]
3138
| Required: String
39+
longer explanation available when compiling with `-explain`
40+
1 error found
3241
scala> val b: Inv[String] = new Inv(1)
33-
-- Error:
42+
-- [E007] Type Mismatch Error: -------------------------------------------------
3443
1 | val b: Inv[String] = new Inv(1)
3544
| ^
3645
| Found: (1 : Int)
3746
| Required: String
47+
longer explanation available when compiling with `-explain`
48+
1 error found
3849
scala> abstract class C { type T; val x: T; val s: Unit = { type T = String; var y: T = x; locally { def f() = { type T = Int; val z: T = y }; f() } }; }
39-
-- Error:
50+
-- [E007] Type Mismatch Error: -------------------------------------------------
4051
1 | abstract class C { type T; val x: T; val s: Unit = { type T = String; var y: T = x; locally { def f() = { type T = Int; val z: T = y }; f() } }; }
4152
| ^
4253
|Found: (C.this.x : C.this.T)
4354
|Required: T²
4455
|
4556
|where: T is a type in class C
4657
| T² is a type in the initializer of value s which is an alias of String
47-
-- Error:
58+
longer explanation available when compiling with `-explain`
59+
-- [E007] Type Mismatch Error: -------------------------------------------------
4860
1 | abstract class C { type T; val x: T; val s: Unit = { type T = String; var y: T = x; locally { def f() = { type T = Int; val z: T = y }; f() } }; }
4961
| ^
5062
|Found: (y : T)
5163
|Required: T²
5264
|
5365
|where: T is a type in the initializer of value s which is an alias of String
5466
| T² is a type in method f which is an alias of Int
67+
longer explanation available when compiling with `-explain`
68+
2 errors found
5569
scala> class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
56-
-- Error:
70+
-- [E008] Not Found Error: -----------------------------------------------------
5771
1 | class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
5872
| ^^^^^^^^
5973
| value barr is not a member of Foo - did you mean foo.bar?
74+
1 error found
6075
scala> val x: List[Int] = "foo" :: List(1)
61-
-- Error:
76+
-- [E007] Type Mismatch Error: -------------------------------------------------
6277
1 | val x: List[Int] = "foo" :: List(1)
6378
| ^^^^^
6479
| Found: ("foo" : String)
6580
| Required: Int
81+
longer explanation available when compiling with `-explain`
82+
1 error found
6683
scala> while ((( foo ))) {}
67-
-- Error:
84+
-- [E006] Not Found Error: -----------------------------------------------------
6885
1 | while ((( foo ))) {}
6986
| ^^^
7087
| Not found: foo
88+
longer explanation available when compiling with `-explain`
89+
1 error found
7190
scala> val a: iDontExist = 1
72-
-- Error:
91+
-- [E006] Not Found Error: -----------------------------------------------------
7392
1 | val a: iDontExist = 1
7493
| ^^^^^^^^^^
7594
| Not found: type iDontExist
95+
longer explanation available when compiling with `-explain`
96+
1 error found
7697
scala> def foo1(x: => Int) = x _
77-
-- Error:
98+
-- [E099] Syntax Error: --------------------------------------------------------
7899
1 | def foo1(x: => Int) = x _
79100
| ^^^
80101
|Only function types can be followed by _ but the current expression has type Int
102+
longer explanation available when compiling with `-explain`
103+
1 error found
81104
scala> def foo2(x: => Int): () => Int = x _
82-
-- Error:
105+
-- [E099] Syntax Error: --------------------------------------------------------
83106
1 | def foo2(x: => Int): () => Int = x _
84107
| ^^^
85108
|Only function types can be followed by _ but the current expression has type Int
109+
longer explanation available when compiling with `-explain`
110+
1 error found
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
scala> val xs = scala.collection.mutable.ListBuffer[Int]
2-
-- Error:
2+
-- [E081] Type Error: ----------------------------------------------------------
33
1 | val xs = scala.collection.mutable.ListBuffer[Int]
44
| ^
55
| Missing parameter type
66
|
77
| I could not infer the type of the parameter elems.
8+
1 error found
89
scala> val xs = scala.collection.mutable.ListBuffer[Int]()
910
val xs: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
scala> try 1
2-
-- Warning:
2+
1 warning found
3+
-- [E000] Syntax Warning: ------------------------------------------------------
34
1 | try 1
45
| ^^^^^
56
| A try without catch or finally is equivalent to putting
67
| its body in a block; no exceptions are handled.
8+
longer explanation available when compiling with `-explain`
79
val res0: Int = 1

compiler/test-resources/repl/i1370

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
scala> object Lives { class Private { def foo1: Any = new Private.C1; def foo2: Any = new Private.C2 }; object Private { class C1 private {}; private class C2 {} } }
2-
-- Error:
2+
-- Error: ----------------------------------------------------------------------
33
1 | object Lives { class Private { def foo1: Any = new Private.C1; def foo2: Any = new Private.C2 }; object Private { class C1 private {}; private class C2 {} } }
44
| ^^^^^^^^^^
55
|constructor C1 cannot be accessed as a member of Lives.Private.C1 from class Private.
6+
1 error found

compiler/test-resources/repl/i2063

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
scala> class Foo extends Bar // with one tab
2-
-- Error:
2+
-- [E006] Not Found Error: -----------------------------------------------------
33
1 | class Foo extends Bar // with one tab
44
| ^^^
55
| Not found: type Bar
6+
longer explanation available when compiling with `-explain`
7+
1 error found
68
scala> class Foo extends Bar // with spaces
7-
-- Error:
9+
-- [E006] Not Found Error: -----------------------------------------------------
810
1 | class Foo extends Bar // with spaces
911
| ^^^
1012
| Not found: type Bar
13+
longer explanation available when compiling with `-explain`
14+
1 error found
1115
scala> class Foo extends Bar // with tabs
12-
-- Error:
16+
-- [E006] Not Found Error: -----------------------------------------------------
1317
1 | class Foo extends Bar // with tabs
1418
| ^^^
1519
| Not found: type Bar
20+
longer explanation available when compiling with `-explain`
21+
1 error found

compiler/test-resources/repl/i2213

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
scala> def x
2-
-- Error:
2+
-- [E019] Syntax Error: --------------------------------------------------------
33
1 | def x
44
| ^
55
| Missing return type
6+
longer explanation available when compiling with `-explain`
67
scala> def x: Int
7-
-- Error:
8+
-- [E067] Syntax Error: --------------------------------------------------------
89
1 | def x: Int
910
| ^
1011
|Declaration of method x not allowed here: only classes can have declared but undefined members
12+
1 error found

compiler/test-resources/repl/i2631

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
scala> class Foo(x : Any) { val foo : Integer = 0; def this() = { this(foo) } }
2-
-- Error:
2+
-- Error: ----------------------------------------------------------------------
33
1 | class Foo(x : Any) { val foo : Integer = 0; def this() = { this(foo) } }
44
| ^^^
5-
| foo is not accessible from constructor arguments
5+
| foo is not accessible from constructor arguments
6+
1 error found

compiler/test-resources/repl/i4184

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ scala> object bar { class Foo }
55
scala> implicit def eqFoo: CanEqual[foo.Foo, foo.Foo] = CanEqual.derived
66
def eqFoo: CanEqual[foo.Foo, foo.Foo]
77
scala> object Bar { new foo.Foo == new bar.Foo }
8-
-- Error:
8+
-- Error: ----------------------------------------------------------------------
99
1 | object Bar { new foo.Foo == new bar.Foo }
1010
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
1111
| Values of types foo.Foo and bar.Foo cannot be compared with == or !=
12+
1 error found

compiler/test-resources/repl/i4217

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
scala> def foo(x: Option[Int]) = x match { case None => }
2-
-- Warning:
2+
1 warning found
3+
-- [E029] Pattern Match Exhaustivity Warning: ----------------------------------
34
1 | def foo(x: Option[Int]) = x match { case None => }
45
| ^
56
| match may not be exhaustive.
67
|
78
| It would fail on pattern case: Some(_)
8-
def foo(x: Option[Int]): Unit
9+
longer explanation available when compiling with `-explain`
10+
def foo(x: Option[Int]): Unit

compiler/test-resources/repl/i4566

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
scala> object test { type ::[A, B]; def a: Int :: Int = ???; def b: Int = a }
2-
-- Error:
2+
-- [E007] Type Mismatch Error: -------------------------------------------------
33
1 | object test { type ::[A, B]; def a: Int :: Int = ???; def b: Int = a }
44
| ^
55
| Found: Int :: Int
66
| Required: Int
7+
longer explanation available when compiling with `-explain`
8+
1 error found

0 commit comments

Comments
 (0)