Skip to content

Commit a93bf0e

Browse files
committed
Remove differences in diagnostic printing in the REPL
1 parent 7a6cabe commit a93bf0e

28 files changed

+140
-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/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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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

compiler/test-resources/repl/errmsgs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,98 @@
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`
910
scala> val y: List[List[String]] = List(List(1))
10-
-- Error:
11+
-- [E007] Type Mismatch Error: -------------------------------------------------
1112
1 | val y: List[List[String]] = List(List(1))
1213
| ^
1314
| Found: (1 : Int)
1415
| Required: String
16+
longer explanation available when compiling with `-explain`
1517
scala> val z: (List[String], List[Int]) = (List(1), List("a"))
16-
-- Error:
18+
-- [E007] Type Mismatch Error: -------------------------------------------------
1719
1 | val z: (List[String], List[Int]) = (List(1), List("a"))
1820
| ^
1921
| Found: (1 : Int)
2022
| Required: String
21-
-- Error:
23+
longer explanation available when compiling with `-explain`
24+
-- [E007] Type Mismatch Error: -------------------------------------------------
2225
1 | val z: (List[String], List[Int]) = (List(1), List("a"))
2326
| ^^^
2427
| Found: ("a" : String)
2528
| Required: Int
29+
longer explanation available when compiling with `-explain`
2630
scala> val a: Inv[String] = new Inv(new Inv(1))
27-
-- Error:
31+
-- [E007] Type Mismatch Error: -------------------------------------------------
2832
1 | val a: Inv[String] = new Inv(new Inv(1))
2933
| ^^^^^^^^^^
3034
| Found: Inv[Int]
3135
| Required: String
36+
longer explanation available when compiling with `-explain`
3237
scala> val b: Inv[String] = new Inv(1)
33-
-- Error:
38+
-- [E007] Type Mismatch Error: -------------------------------------------------
3439
1 | val b: Inv[String] = new Inv(1)
3540
| ^
3641
| Found: (1 : Int)
3742
| Required: String
43+
longer explanation available when compiling with `-explain`
3844
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:
45+
-- [E007] Type Mismatch Error: -------------------------------------------------
4046
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() } }; }
4147
| ^
4248
|Found: (C.this.x : C.this.T)
4349
|Required: T²
4450
|
4551
|where: T is a type in class C
4652
| T² is a type in the initializer of value s which is an alias of String
47-
-- Error:
53+
longer explanation available when compiling with `-explain`
54+
-- [E007] Type Mismatch Error: -------------------------------------------------
4855
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() } }; }
4956
| ^
5057
|Found: (y : T)
5158
|Required: T²
5259
|
5360
|where: T is a type in the initializer of value s which is an alias of String
5461
| T² is a type in method f which is an alias of Int
62+
longer explanation available when compiling with `-explain`
5563
scala> class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
56-
-- Error:
64+
-- [E008] Not Found Error: -----------------------------------------------------
5765
1 | class Foo() { def bar: Int = 1 }; val foo = new Foo(); foo.barr
5866
| ^^^^^^^^
5967
| value barr is not a member of Foo - did you mean foo.bar?
6068
scala> val x: List[Int] = "foo" :: List(1)
61-
-- Error:
69+
-- [E007] Type Mismatch Error: -------------------------------------------------
6270
1 | val x: List[Int] = "foo" :: List(1)
6371
| ^^^^^
6472
| Found: ("foo" : String)
6573
| Required: Int
74+
longer explanation available when compiling with `-explain`
6675
scala> while ((( foo ))) {}
67-
-- Error:
76+
-- [E006] Not Found Error: -----------------------------------------------------
6877
1 | while ((( foo ))) {}
6978
| ^^^
7079
| Not found: foo
80+
longer explanation available when compiling with `-explain`
7181
scala> val a: iDontExist = 1
72-
-- Error:
82+
-- [E006] Not Found Error: -----------------------------------------------------
7383
1 | val a: iDontExist = 1
7484
| ^^^^^^^^^^
7585
| Not found: type iDontExist
86+
longer explanation available when compiling with `-explain`
7687
scala> def foo1(x: => Int) = x _
77-
-- Error:
88+
-- [E099] Syntax Error: --------------------------------------------------------
7889
1 | def foo1(x: => Int) = x _
7990
| ^^^
8091
|Only function types can be followed by _ but the current expression has type Int
92+
longer explanation available when compiling with `-explain`
8193
scala> def foo2(x: => Int): () => Int = x _
82-
-- Error:
94+
-- [E099] Syntax Error: --------------------------------------------------------
8395
1 | def foo2(x: => Int): () => Int = x _
8496
| ^^^
8597
|Only function types can be followed by _ but the current expression has type Int
98+
longer explanation available when compiling with `-explain`

compiler/test-resources/repl/errorThenValid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
scala> try 1
2-
-- Warning:
2+
-- [E000] Syntax Warning: ------------------------------------------------------
33
1 | try 1
44
| ^^^^^
55
| A try without catch or finally is equivalent to putting
66
| its body in a block; no exceptions are handled.
7+
longer explanation available when compiling with `-explain`
78
val res0: Int = 1

compiler/test-resources/repl/i1370

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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.

compiler/test-resources/repl/i2063

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
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`
67
scala> class Foo extends Bar // with spaces
7-
-- Error:
8+
-- [E006] Not Found Error: -----------------------------------------------------
89
1 | class Foo extends Bar // with spaces
910
| ^^^
1011
| Not found: type Bar
12+
longer explanation available when compiling with `-explain`
1113
scala> class Foo extends Bar // with tabs
12-
-- Error:
14+
-- [E006] Not Found Error: -----------------------------------------------------
1315
1 | class Foo extends Bar // with tabs
1416
| ^^^
1517
| Not found: type Bar
18+
longer explanation available when compiling with `-explain`

compiler/test-resources/repl/i2213

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
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

compiler/test-resources/repl/i2631

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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

compiler/test-resources/repl/i4184

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ 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 !=

compiler/test-resources/repl/i4217

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

compiler/test-resources/repl/i4566

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
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`

compiler/test-resources/repl/i5733

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
scala> abstract class F { def f(arg: Any): Unit; override def toString = "F" }
22
// defined class F
33
scala> val f: F = println
4-
-- Warning:
4+
-- Warning: --------------------------------------------------------------------
55
1 | val f: F = println
66
| ^^^^^^^
77
|method println is eta-expanded even though F does not have the @FunctionalInterface annotation.
8-
val f: F = F
8+
val f: F = F

compiler/test-resources/repl/i6474

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ val res0: (Any, Int) = (1,2)
99
scala> ((1, 2): Foo2.T[Int][Int]): Foo2.T[Any][Int]
1010
val res1: (Any, Int) = (1,2)
1111
scala> (1, 2): Foo3.T[Int][Int]
12-
-- Error:
12+
-- [E056] Syntax Error: --------------------------------------------------------
1313
1 | (1, 2): Foo3.T[Int][Int]
1414
| ^^^^^^^^^^^^^^^^
1515
| Missing type parameter for Foo3.T[Int][Int]

0 commit comments

Comments
 (0)