Skip to content

Commit

Permalink
Improve -explain rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Jan 27, 2022
1 parent e523c8d commit d24684b
Show file tree
Hide file tree
Showing 71 changed files with 459 additions and 320 deletions.
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ object ConsoleReporter {
/** Prints the message with the given position indication. */
def doReport(dia: Diagnostic)(using Context): Unit = {
printMessage(messageAndPos(dia))
if Diagnostic.shouldExplain(dia) then
printMessage(explanation(dia.msg))
else if dia.msg.canExplain then
printMessage("\nlonger explanation available when compiling with `-explain`")
}
}
}
14 changes: 14 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ trait MessageRendering {
else sb.append(msg.message)
if (dia.isVerbose)
appendFilterHelp(dia, sb)

if Diagnostic.shouldExplain(dia) then
sb.append(EOL).append(newBox())
sb.append(EOL).append(offsetBox).append(" Explanation")
sb.append(EOL).append(newBox(soft = true))
dia.msg.explanation.split(EOL).foreach { line =>
sb.append(EOL).append(offsetBox).append(if line.isEmpty then "" else " ").append(line)
}
sb.append(EOL).append(endBox)
else if dia.msg.canExplain then
sb.append(EOL).append(newBox())
sb.append(EOL).append(offsetBox).append(" longer explanation available when compiling with `-explain`")
sb.append(EOL).append(endBox)

sb.toString
}

Expand Down
9 changes: 4 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,17 @@ object ErrorReporting {
|conforms to
| $expected
|but the comparison trace ended with `false`:
"""
|"""
val c = ctx.typerState.constraint
val constraintText =
if c.domainLambdas.isEmpty then
"the empty constraint"
else
i"""a constraint with:
|$c"""
i"""
|${TypeComparer.explained(_.isSubType(found, expected), header)}
|
|The tests were made under $constraintText"""
i"""${TypeComparer.explained(_.isSubType(found, expected), header)}
|
|The tests were made under $constraintText"""

/** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing
* all occurrences of `${X}` where `X` is in `paramNames` with the
Expand Down
5 changes: 3 additions & 2 deletions tests/neg-custom-args/explicit-nulls/byname-nullables.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
| ^
| Found: (x : String | Null)
| Required: String

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- Error: tests/neg-custom-args/explicit-nulls/byname-nullables.scala:43:32 --------------------------------------------
43 | if x != null then f(identity(x), 1) // error: dropping not null check fails typing
| ^^^^^^^^^^^
Expand Down
10 changes: 6 additions & 4 deletions tests/neg-custom-args/explicit-nulls/i7883.check
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
6 | case r(hd, tl) => Some((hd, tl)) // error // error // error
| ^^
| Not found: hd

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
-- [E006] Not Found Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:34 ---------------------------------------
6 | case r(hd, tl) => Some((hd, tl)) // error // error // error
| ^^
| Not found: tl

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
97 changes: 48 additions & 49 deletions tests/neg-custom-args/i11637.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,55 @@
11 | var h = new HKT3_1[FunctorImpl](); // error // error
| ^
| Type argument test2.FunctorImpl does not conform to upper bound [Generic2[T <: String] <: Set[T]] =>> Any

Explanation
===========

I tried to show that
test2.FunctorImpl
conforms to
[Generic2[T <: String] <: Set[T]] =>> Any
but the comparison trace ended with `false`:

==> test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any
==> type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]]
==> [T <: String] =>> Set[T] <: Iterable
==> type bounds [] <: type bounds [ <: String]
==> Any <: String
==> Any <: String
<== Any <: String = false
<== Any <: String = false
<== type bounds [] <: type bounds [ <: String] = false
<== [T <: String] =>> Set[T] <: Iterable = false
<== type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]] = false
<== test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any = false

The tests were made under the empty constraint

|--------------------------------------------------------------------------------------------------------------------
| Explanation
|····················································································································
| I tried to show that
| test2.FunctorImpl
| conforms to
| [Generic2[T <: String] <: Set[T]] =>> Any
| but the comparison trace ended with `false`:
|
| ==> test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any
| ==> type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]]
| ==> [T <: String] =>> Set[T] <: Iterable
| ==> type bounds [] <: type bounds [ <: String]
| ==> Any <: String
| ==> Any <: String
| <== Any <: String = false
| <== Any <: String = false
| <== type bounds [] <: type bounds [ <: String] = false
| <== [T <: String] =>> Set[T] <: Iterable = false
| <== type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]] = false
| <== test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any = false
|
| The tests were made under the empty constraint
·--------------------------------------------------------------------------------------------------------------------
-- [E057] Type Mismatch Error: tests/neg-custom-args/i11637.scala:11:21 ------------------------------------------------
11 | var h = new HKT3_1[FunctorImpl](); // error // error
| ^
| Type argument test2.FunctorImpl does not conform to upper bound [Generic2[T <: String] <: Set[T]] =>> Any

Explanation
===========

I tried to show that
test2.FunctorImpl
conforms to
[Generic2[T <: String] <: Set[T]] =>> Any
but the comparison trace ended with `false`:
==> test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any
==> type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]]
==> [T <: String] =>> Set[T] <: Iterable
==> type bounds [] <: type bounds [ <: String]
==> Any <: String
==> Any <: String
<== Any <: String = false
<== Any <: String = false
<== type bounds [] <: type bounds [ <: String] = false
<== [T <: String] =>> Set[T] <: Iterable = false
<== type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]] = false
<== test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any = false

The tests were made under the empty constraint
|--------------------------------------------------------------------------------------------------------------------
| Explanation
|····················································································································
| I tried to show that
| test2.FunctorImpl
| conforms to
| [Generic2[T <: String] <: Set[T]] =>> Any
| but the comparison trace ended with `false`:
|
| ==> test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any
| ==> type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]]
| ==> [T <: String] =>> Set[T] <: Iterable
| ==> type bounds [] <: type bounds [ <: String]
| ==> Any <: String
| ==> Any <: String
| <== Any <: String = false
| <== Any <: String = false
| <== type bounds [] <: type bounds [ <: String] = false
| <== [T <: String] =>> Set[T] <: Iterable = false
| <== type bounds [[T <: String] <: Set[T]] <: type bounds [[T] <: Iterable[T]] = false
| <== test2.FunctorImpl <: [Generic2[T <: String] <: Set[T]] =>> Any = false
|
| The tests were made under the empty constraint
·--------------------------------------------------------------------------------------------------------------------
10 changes: 6 additions & 4 deletions tests/neg-custom-args/i13026.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
| ^^^^^^^^^^^^
| Found: ("not an int" : String)
| Required: Int

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
-- [E007] Type Mismatch Error: tests/neg-custom-args/i13026.scala:2:13 -------------------------------------------------
2 |val y: Int = "not an int" // error
| ^^^^^^^^^^^^
| Found: ("not an int" : String)
| Required: Int

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
-- [E008] Not Found Error: tests/neg-custom-args/i13026.scala:3:20 -----------------------------------------------------
3 |def foo(x: Any) = x.foo // error
| ^^^^^
Expand Down
5 changes: 3 additions & 2 deletions tests/neg-custom-args/i13838.check
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
| You can change the behavior by setting the `-Ximplicit-search-limit` value.
| Smaller values cause the search to fail faster.
| Larger values might make a very large search problem succeed.

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
5 changes: 3 additions & 2 deletions tests/neg-custom-args/jdk-9-app.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
4 | println(ProcessHandle.current().pid()) // error: not found
| ^^^^^^^^^^^^^
| Not found: ProcessHandle

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
10 changes: 6 additions & 4 deletions tests/neg-custom-args/kind-projector-underscores.check
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
10 | type -_ = Int // error -_ not allowed as a type def name without backticks
| ^
| =, >:, or <: expected, but '_' found

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- [E095] Syntax Error: tests/neg-custom-args/kind-projector-underscores.scala:11:8 ------------------------------------
11 | type +_ = Int // error +_ not allowed as a type def name without backticks
| ^
| =, >:, or <: expected, but '_' found

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- Error: tests/neg-custom-args/kind-projector-underscores.scala:14:51 -------------------------------------------------
14 |class BacktickUnderscoreIsNotFine extends Foo[List[`_`]] // error wildcard invalid as backquoted identifier
| ^
Expand Down
10 changes: 6 additions & 4 deletions tests/neg-custom-args/nowarn/nowarn-parser-error.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
3 | def def // error
| ^^^
| an identifier expected, but 'def' found

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
-- [E000] Syntax Warning: tests/neg-custom-args/nowarn/nowarn-parser-error.scala:2:10 ----------------------------------
2 | def a = try 1 // warn
| ^^^^^
| A try without catch or finally is equivalent to putting
| its body in a block; no exceptions are handled.

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
5 changes: 3 additions & 2 deletions tests/neg-custom-args/nowarn/nowarn-typer-error.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
4 | def t1 = / // error
| ^
| Not found: /

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
30 changes: 18 additions & 12 deletions tests/neg-custom-args/nowarn/nowarn.check
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@
| ^^^^^
| A try without catch or finally is equivalent to putting
| its body in a block; no exceptions are handled.

longer explanation available when compiling with `-explain`
|---------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·---------------------------------------------------------------------------------------------------------------------
-- [E000] Syntax Warning: tests/neg-custom-args/nowarn/nowarn.scala:23:25 ----------------------------------------------
23 |@nowarn(o.inl) def t2d = try 1 // two warnings (`inl` is not a compile-time constant)
| ^^^^^
| A try without catch or finally is equivalent to putting
| its body in a block; no exceptions are handled.

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- [E000] Syntax Warning: tests/neg-custom-args/nowarn/nowarn.scala:31:26 ----------------------------------------------
31 |@nowarn("id=1") def t4d = try 1 // error and warning (unused nowarn, wrong id)
| ^^^^^
| A try without catch or finally is equivalent to putting
| its body in a block; no exceptions are handled.

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- [E000] Syntax Warning: tests/neg-custom-args/nowarn/nowarn.scala:33:28 ----------------------------------------------
33 |@nowarn("verbose") def t5 = try 1 // warning with details
| ^^^^^
Expand All @@ -27,14 +30,16 @@ longer explanation available when compiling with `-explain`
Matching filters for @nowarn or -Wconf:
- id=E0
- name=EmptyCatchOrFinallyBlock

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- [E129] Potential Issue Warning: tests/neg-custom-args/nowarn/nowarn.scala:13:11 -------------------------------------
13 |def t2 = { 1; 2 } // warning (the invalid nowarn doesn't silence anything)
| ^
| A pure expression does nothing in statement position; you may be omitting necessary parentheses

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- Warning: tests/neg-custom-args/nowarn/nowarn.scala:12:8 -------------------------------------------------------------
12 |@nowarn("wat?") // warning (typer, invalid filter)
| ^^^^^^
Expand All @@ -44,8 +49,9 @@ longer explanation available when compiling with `-explain`
16 |def t2a = { 1; 2 } // warning (invalid nowarn doesn't silence)
| ^
| A pure expression does nothing in statement position; you may be omitting necessary parentheses

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
-- Warning: tests/neg-custom-args/nowarn/nowarn.scala:15:8 -------------------------------------------------------------
15 |@nowarn(t1a.toString) // warning (typer, argument not a compile-time constant)
| ^^^^^^^^^^^^
Expand Down
5 changes: 3 additions & 2 deletions tests/neg-macros/beta-reduce-inline-result.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Found: Int
| Required: (4 : Int)

longer explanation available when compiling with `-explain`
|--------------------------------------------------------------------------------------------------------------------
| longer explanation available when compiling with `-explain`
·--------------------------------------------------------------------------------------------------------------------
Loading

0 comments on commit d24684b

Please sign in to comment.