From d2b620541b18bb50d2a2b89194e1778c64bba567 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Mon, 3 Oct 2016 18:21:28 +0200 Subject: Insert message "inline" into multiline code at point --- src/dotty/tools/dotc/printing/Formatting.scala | 10 +++++-- src/dotty/tools/dotc/printing/Highlighting.scala | 4 --- .../tools/dotc/reporting/ConsoleReporter.scala | 12 ++++---- .../tools/dotc/reporting/diagnostic/Message.scala | 8 +++++ .../tools/dotc/reporting/diagnostic/messages.scala | 34 +++++++--------------- src/dotty/tools/dotc/util/SourcePosition.scala | 6 ++++ 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/dotty/tools/dotc/printing/Formatting.scala b/src/dotty/tools/dotc/printing/Formatting.scala index 9cbf07914..76d2bdc18 100644 --- a/src/dotty/tools/dotc/printing/Formatting.scala +++ b/src/dotty/tools/dotc/printing/Formatting.scala @@ -10,7 +10,7 @@ import scala.annotation.switch import scala.util.control.NonFatal import reporting.diagnostic.MessageContainer import util.DiffUtil -import Highlighting.{ highlightToString => _, _ } +import Highlighting._ import SyntaxHighlighting._ object Formatting { @@ -165,7 +165,11 @@ object Formatting { } } - /** Turns a `Seen => String` to produce a `where: T is...` clause */ + /** Turns a `Seen` into a `String` to produce an explanation for types on the + * form `where: T is...` + * + * @return string disambiguating types + */ private def explanations(seen: Seen)(implicit ctx: Context): String = { def needsExplanation(entry: Recorded) = entry match { case param: PolyParam => ctx.typerState.constraint.contains(param) @@ -245,7 +249,7 @@ object Formatting { val exp = wrapNonSensical(expected, expected.show) (found, expected) match { - case (_: RefinedType, _: RefinedType) => + case (_: RefinedType, _: RefinedType) if ctx.settings.color.value != "never" => DiffUtil.mkColoredTypeDiff(fnd, exp) case _ => (hl"$fnd", hl"$exp") diff --git a/src/dotty/tools/dotc/printing/Highlighting.scala b/src/dotty/tools/dotc/printing/Highlighting.scala index 13e55722f..3bda7fb7a 100644 --- a/src/dotty/tools/dotc/printing/Highlighting.scala +++ b/src/dotty/tools/dotc/printing/Highlighting.scala @@ -9,10 +9,6 @@ object Highlighting { implicit def highlightShow(h: Highlight)(implicit ctx: Context): String = h.show - implicit def highlightToString(h: Highlight): String = - h.toString - implicit def hbufToString(hb: HighlightBuffer): String = - hb.toString abstract class Highlight(private val highlight: String) { def text: String diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 6ebd53bea..82edd6a83 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -32,9 +32,10 @@ class ConsoleReporter( def stripColor(str: String): String = str.replaceAll("\u001B\\[[;\\d]*m", "") - def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], Int) = { + def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { var maxLen = Int.MinValue - val lines = pos.lines + def render(xs: List[Int]) = + xs.map(pos.source.offsetToLine(_)) .map { lineNbr => val prefix = s"${lineNbr + 1} |" maxLen = math.max(maxLen, prefix.length) @@ -45,7 +46,8 @@ class ConsoleReporter( hl"$lnum$line" } - (lines, maxLen) + val (before, after) = pos.beforeAndAfterPoint + (render(before), render(after), maxLen) } def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context) = { @@ -95,11 +97,11 @@ class ConsoleReporter( def printMessageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): Unit = { printMessage(posStr(pos, diagnosticLevel, msg)) if (pos.exists) { - val (srcLines, offset) = sourceLines(pos) + val (srcBefore, srcAfter, offset) = sourceLines(pos) val marker = columnMarker(pos, offset) val err = errorMsg(pos, msg.msg, offset) - printMessage((srcLines ::: marker :: err :: Nil).mkString("\n")) + printMessage((srcBefore ::: marker :: err :: srcAfter).mkString("\n")) } else printMessage(msg.msg) } diff --git a/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index bdc899ea8..8b1f65673 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -15,6 +15,14 @@ object Message { new NoExplanation(str) } +/** A `Message` contains all semantic information necessary to easily + * comprehend what caused the message to be logged. Each message can be turned + * into a `MessageContainer` which contains the log level and can later be + * consumed by a subclass of `Reporter`. + * + * @param errorId a unique number identifying the message, this will later be + * used to reference documentation online + */ abstract class Message(val errorId: Int) { self => import messages._ diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index e2b99af41..cc062ff92 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -90,8 +90,10 @@ object messages { } val code1 = - s"""|try $tryString catch { - | case t: Throwable => ??? + s"""|import scala.util.control.NonFatal + | + |try $tryString catch { + | case NonFatal(e) => ??? |}""".stripMargin val code2 = @@ -108,7 +110,10 @@ object messages { |It is also possible to follow a ${"try"} immediately by a ${"finally"} - letting the |exception propagate - but still allowing for some clean up in ${"finally"}: | - |$code2""".stripMargin + |$code2 + | + |It is recommended to use the ${"NonFatal"} extractor to catch all exceptions as it + |correctly handles transfer functions like ${"return"}.""".stripMargin } } @@ -133,29 +138,10 @@ object messages { val kind = "Syntax" val msg = hl"""${"with"} as a type operator has been deprecated; use `&' instead""" - val explanation = { - val codeBlock1 = - """|trait A { - | type T = Int - |} - | - |trait B { - | type T = Double - |}""".stripMargin - + val explanation = hl"""|Dotty introduces intersection types - `&' types. These replace the |use of the ${"with"} keyword. There are a few differences in - |semantics between intersection types and using `${"with"}'. - | - |`${"A with B"}' is ordered, `${"A & B"}' is not. - | - |In: - | - |$codeBlock1 - | - |The type of `${"T"}' in `${"A with B"}' is ${"Int"} whereas in `${"A & B"}' - |the type of `${"T"}' is ${"Int & Double"}.""".stripMargin - } + |semantics between intersection types and using `${"with"}'.""".stripMargin } case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) diff --git a/src/dotty/tools/dotc/util/SourcePosition.scala b/src/dotty/tools/dotc/util/SourcePosition.scala index a64f44417..595ea34ca 100644 --- a/src/dotty/tools/dotc/util/SourcePosition.scala +++ b/src/dotty/tools/dotc/util/SourcePosition.scala @@ -22,9 +22,15 @@ extends interfaces.SourcePosition { case xs => xs } + def lineOffsets: List[Int] = + lines.map(source.lineToOffset(_)) + def lineContent(lineNumber: Int): String = source.lineContent(source.lineToOffset(lineNumber)) + def beforeAndAfterPoint: (List[Int], List[Int]) = + lineOffsets.partition(_ < point) + /** The column of the position, starting at 0 */ def column: Int = source.column(point) -- cgit v1.2.3