From f5ad8492d076051c8805370c05610d8294ccb241 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Tue, 27 Sep 2016 16:07:56 +0200 Subject: Fix reporting of ErrorTypes in highlighted segments --- src/dotty/tools/dotc/core/Decorators.scala | 4 ++ src/dotty/tools/dotc/printing/Formatting.scala | 50 ++++++++++++++++------ .../tools/dotc/printing/SyntaxHighlighting.scala | 14 ------ .../tools/dotc/reporting/ConsoleReporter.scala | 2 +- .../reporting/diagnostic/MessageContainer.scala | 2 +- .../tools/dotc/reporting/diagnostic/messages.scala | 4 +- src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/repl/errmsgs.check | 16 +++---- tests/repl/imports.check | 4 +- 9 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index 3bf17730a..b0f1f0c98 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -176,6 +176,10 @@ object Decorators { */ def ex(args: Any*)(implicit ctx: Context): String = explained2(implicit ctx => em(args: _*)) + + /** Formatter that adds syntax highlighting to all interpolated values */ + def hl(args: Any*)(implicit ctx: Context): String = + new SyntaxFormatter(sc).assemble(args) } } diff --git a/src/dotty/tools/dotc/printing/Formatting.scala b/src/dotty/tools/dotc/printing/Formatting.scala index dd391ea80..41bd91607 100644 --- a/src/dotty/tools/dotc/printing/Formatting.scala +++ b/src/dotty/tools/dotc/printing/Formatting.scala @@ -69,21 +69,40 @@ object Formatting { * message composition methods, this is crucial. */ class ErrorMessageFormatter(sc: StringContext) extends StringFormatter(sc) { + override protected def showArg(arg: Any)(implicit ctx: Context): String = + wrapNonSensical(arg, super.showArg(arg)) + } + + class SyntaxFormatter(sc: StringContext) extends StringFormatter(sc) { override protected def showArg(arg: Any)(implicit ctx: Context): String = { - import MessageContainer._ - def isSensical(arg: Any): Boolean = arg match { - case tpe: Type => - tpe.exists && !tpe.isErroneous - case sym: Symbol if sym.isCompleted => - sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info.exists - case _ => true + arg match { + case arg: Showable => + val highlighted = + SyntaxHighlighting(wrapNonSensical(arg, super.showArg(arg))) + new String(highlighted.toArray) + case hl: Highlight => + hl.show + case hb: HighlightBuffer => + hb.toString + case _ => super.showArg(arg) } - val str = super.showArg(arg) - if (isSensical(arg)) str - else nonSensicalStartTag + str + nonSensicalEndTag } } + private def wrapNonSensical(arg: Any, str: String)(implicit ctx: Context): String = { + import MessageContainer._ + def isSensical(arg: Any): Boolean = arg match { + case tpe: Type => + tpe.exists && !tpe.isErroneous + case sym: Symbol if sym.isCompleted => + sym.info != ErrorType && sym.info != TypeAlias(ErrorType) && sym.info.exists + case _ => true + } + + if (isSensical(arg)) str + else nonSensicalStartTag + str + nonSensicalEndTag + } + private type Recorded = AnyRef /*Symbol | PolyParam*/ private class Seen extends mutable.HashMap[String, List[Recorded]] { @@ -117,7 +136,7 @@ object Formatting { } /** Create explanation for single `Recorded` type or symbol */ - def explanation(entry: Recorded)(implicit ctx: Context): String = { + def explanation(entry: AnyRef)(implicit ctx: Context): String = { def boundStr(bound: Type, default: ClassSymbol, cmp: String) = if (bound.isRef(default)) "" else i"$cmp $bound" @@ -221,11 +240,14 @@ object Formatting { * @return the (found, expected) with coloring to highlight the difference */ def typeDiff(found: Type, expected: Type)(implicit ctx: Context): (String, String) = { + val fnd = wrapNonSensical(found, found.show) + val exp = wrapNonSensical(expected, found.show) + (found, expected) match { - case (rf1: RefinedType, rf2: RefinedType) => - DiffUtil.mkColoredTypeDiff(rf1.show, rf2.show) + case (_: RefinedType, _: RefinedType) => + DiffUtil.mkColoredTypeDiff(fnd, exp) case _ => - (hl"${found.show}", hl"${expected.show}") + (hl"$fnd", hl"$exp") } } } diff --git a/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala b/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala index 7d4d12394..86f34e64d 100644 --- a/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala +++ b/src/dotty/tools/dotc/printing/SyntaxHighlighting.scala @@ -11,20 +11,6 @@ import Highlighting.{Highlight, HighlightBuffer} /** This object provides functions for syntax highlighting in the REPL */ object SyntaxHighlighting { - implicit class SyntaxFormatting(val sc: StringContext) extends AnyVal { - def hl(args: Any*)(implicit ctx: Context): String = - sc.s(args.map ({ - case hl: Highlight => - hl.show - case hb: HighlightBuffer => - hb.toString - case x if ctx.settings.color.value != "never" => - new String(apply(x.toString).toArray) - case x => - x.toString - }): _*) - } - val NoColor = Console.RESET val CommentColor = Console.BLUE val KeywordColor = Console.YELLOW diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 321559e77..261357924 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -4,7 +4,7 @@ package reporting import scala.collection.mutable import util.SourcePosition -import core.Contexts._ +import core.Contexts._, core.Decorators._ import Reporter._ import java.io.{ BufferedReader, IOException, PrintWriter } import scala.reflect.internal.util._ diff --git a/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala index d15c1d2f1..7bb092da2 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala @@ -41,7 +41,7 @@ class MessageContainer( /** The message to report */ def message: String = { if (myMsg == null) { - myMsg = msgFn.msg + myMsg = msgFn.msg.replaceAll("\u001B\\[[;\\d]*m", "") if (myMsg.contains(nonSensicalStartTag)) { myIsNonSensical = true // myMsg might be composed of several d"..." invocations -> nested diff --git a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 01cf00cf7..76b2fd3e9 100644 --- a/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -202,13 +202,13 @@ object messages { } } - case class MissingIdent(tree: untpd.Ident, treeKind: String, name: Name)(implicit ctx: Context) + case class MissingIdent(tree: untpd.Ident, treeKind: String, name: String)(implicit ctx: Context) extends Message("E005") { val kind = "Missing Identifier" val msg = em"not found: $treeKind$name" val explanation = { - hl"""|An identifier for `${name.show}` is missing. This means that something + hl"""|An identifier for `$treeKind$name` is missing. This means that something |has either been misspelt or you're forgetting an import""".stripMargin } } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 0cc04613a..a4dc2f871 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -331,7 +331,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (rawType.exists) ensureAccessible(rawType, superAccess = false, tree.pos) else { - error(new MissingIdent(tree, kind, name), tree.pos) + error(new MissingIdent(tree, kind, name.show), tree.pos) ErrorType } diff --git a/tests/repl/errmsgs.check b/tests/repl/errmsgs.check index b8cff5ba2..b791123f4 100644 --- a/tests/repl/errmsgs.check +++ b/tests/repl/errmsgs.check @@ -5,34 +5,34 @@ scala> val x: List[String] = List(1) 3:val x: List[String] = List(1) ^ found: Int(1) - required: String + required: Int(1) scala> val y: List[List[String]] = List(List(1)) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- 3:val y: List[List[String]] = List(List(1)) ^ found: Int(1) - required: String + required: Int(1) scala> val z: (List[String], List[Int]) = (List(1), List("a")) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- 3:val z: (List[String], List[Int]) = (List(1), List("a")) ^ found: Int(1) - required: String + required: Int(1) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- 3:val z: (List[String], List[Int]) = (List(1), List("a")) ^^^ found: String("a") - required: Int + required: String("a") scala> val a: Inv[String] = new Inv(new Inv(1)) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- 4:val a: Inv[String] = new Inv(new Inv(1)) ^^^^^ found: Inv[T] - required: String + required: Inv[T] where: T is a type variable with constraint >: Int(1) scala> val b: Inv[String] = new Inv(1) @@ -40,7 +40,7 @@ scala> val b: Inv[String] = new Inv(1) 4:val b: Inv[String] = new Inv(1) ^ found: Int(1) - required: String + required: Int(1) scala> abstract class C { type T @@ -61,7 +61,7 @@ scala> abstract class C { 8: var y: T = x ^ found: C.this.T(C.this.x) - required: T' + required: C.this.T(C.this.x) where: T is a type in class C T' is a type in the initalizer of value s which is an alias of String @@ -69,7 +69,7 @@ scala> abstract class C { 12: val z: T = y ^ found: T(y) - required: T' + required: T(y) where: T is a type in the initalizer of value s which is an alias of String T' is a type in method f which is an alias of Int diff --git a/tests/repl/imports.check b/tests/repl/imports.check index 2e8d5dcf9..817adae87 100644 --- a/tests/repl/imports.check +++ b/tests/repl/imports.check @@ -11,13 +11,13 @@ scala> buf += xs 10:buf += xs ^^ found: scala.collection.immutable.List[Int](o.xs) - required: String + required: scala.collection.immutable.List[Int](o.xs) -- [E006] Type Mismatch Error: ------------------------------------------------------------------------------- 10:buf += xs ^^^^^^^^^ found: String - required: scala.collection.mutable.ListBuffer[Int] + required: String scala> buf ++= xs res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3) -- cgit v1.2.3