aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-08-14 16:09:18 +0200
committerMartin Odersky <odersky@gmail.com>2013-08-14 16:09:18 +0200
commitf1601119c092d9a47795a29a83afa6ff9e5b0fda (patch)
tree72cf54132d7f227790d13e3502bd50d26aaf26ae
parentf19250b1a123aa63cf8f14096bfd8e29e7e548b2 (diff)
downloaddotty-f1601119c092d9a47795a29a83afa6ff9e5b0fda.tar.gz
dotty-f1601119c092d9a47795a29a83afa6ff9e5b0fda.tar.bz2
dotty-f1601119c092d9a47795a29a83afa6ff9e5b0fda.zip
New error reporting scheme.
new string interpolator "i" for info strings. Computing an info string performs some compiler specific display operations and also allows to suppress an error message entirely if it refers to something non-sensical.
-rw-r--r--src/dotty/tools/dotc/reporting/ConsoleReporter.scala8
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala72
-rw-r--r--src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala14
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala59
4 files changed, 104 insertions, 49 deletions
diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
index ae677ecdc..6b3f08cf0 100644
--- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
@@ -40,11 +40,11 @@ class ConsoleReporter(
}
}
- override def doReport(d: Diagnostic)(implicit ctx: Context) {
- if (d.severity != ERROR || count(d.severity.level) <= ErrorLimit)
+ override def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
+ if (d.severity != ERROR || count(d.severity.level) <= ErrorLimit && !d.isSuppressed) {
printMessageAndPos(label(d.severity) + d.msg, d.pos)
- if (d.severity.level > INFO.level && ctx.settings.prompt.value) displayPrompt()
- }
+ if (d.severity.level > INFO.level && ctx.settings.prompt.value) displayPrompt()
+ }
def displayPrompt(): Unit = {
writer.print("\na)bort, s)tack, r)esume: ")
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 5ebc5934f..be2136655 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -12,12 +12,33 @@ import java.lang.System.currentTimeMillis
object Reporter {
- class Diagnostic(msgFn: => String, val pos: SourcePosition, val severity: Severity) extends Exception {
- lazy val msg: String = msgFn
+ class Diagnostic(msgFn: => String, val pos: SourcePosition, val severity: Severity, base: ContextBase) extends Exception {
+ private var myMsg: String = null
+ private var myIsSuppressed: Boolean = false
+ def msg: String = {
+ if (myMsg == null)
+ try myMsg = msgFn
+ catch {
+ case ex: SuppressedMessage =>
+ val saved = base.suppressNonSensicalErrors
+ base.suppressNonSensicalErrors = false
+ try myMsg = msgFn
+ finally base.suppressNonSensicalErrors = saved
+ }
+ myMsg
+ }
+ def isSuppressed = { msg; myIsSuppressed }
override def toString = s"$severity at $pos: $msg"
override def getMessage() = msg
+
+ def promotedSeverity(implicit ctx: Context): Severity =
+ if (isConditionalWarning(severity) && enablingOption(severity).value) WARNING
+ else severity
}
+ def Diagnostic(msgFn: => String, pos: SourcePosition, severity: Severity)(implicit ctx: Context) =
+ new Diagnostic(msgFn, pos, severity, ctx.base)
+
class Severity(val level: Int) extends AnyVal {
override def toString = this match {
case VerboseINFO => "VerboseINFO"
@@ -42,6 +63,14 @@ object Reporter {
DeprecationWARNING.level <= s.level && s.level <= FeatureWARNING.level
val conditionalWarnings = List(DeprecationWARNING, UncheckedWARNING, FeatureWARNING)
+
+ private def enablingOption(warning: Severity)(implicit ctx: Context) = warning match {
+ case DeprecationWARNING => ctx.settings.deprecation
+ case UncheckedWARNING => ctx.settings.unchecked
+ case FeatureWARNING => ctx.settings.feature
+ }
+
+ class SuppressedMessage extends Exception
}
import Reporter._
@@ -50,28 +79,28 @@ trait Reporting { this: Context =>
/** For sending messages that are printed only if -verbose is set */
def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, VerboseINFO))
+ reporter.report(Diagnostic(msg, pos, VerboseINFO))
def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, INFO))
+ reporter.report(Diagnostic(msg, pos, INFO))
def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, DeprecationWARNING))
+ reporter.report(Diagnostic(msg, pos, DeprecationWARNING))
def uncheckedWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, UncheckedWARNING))
+ reporter.report(Diagnostic(msg, pos, UncheckedWARNING))
def featureWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, FeatureWARNING))
+ reporter.report(Diagnostic(msg, pos, FeatureWARNING))
def warning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, WARNING))
+ reporter.report(Diagnostic(msg, pos, WARNING))
def error(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(new Diagnostic(msg, pos, ERROR))
+ reporter.report(Diagnostic(msg, pos, ERROR))
def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
- reporter.incomplete(new Diagnostic(msg, pos, ERROR))(ctx)
+ reporter.incomplete(Diagnostic(msg, pos, ERROR))(ctx)
def log(msg: => String): Unit =
if (this.settings.log.value.containsPhase(phase))
@@ -134,7 +163,7 @@ abstract class Reporter {
/** Report a diagnostic */
protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit
- /** Whether very long lines can be truncated. This exists so important
+ /** Whether very long lines can be truncated. This exists so important
* debugging information (like printing the classpath) is not rendered
* invisible due to the max message length.
*/
@@ -156,28 +185,19 @@ abstract class Reporter {
finally incompleteHandler = saved
}
- protected def isHidden(s: Severity, pos: SourcePosition)(implicit ctx: Context) = s match {
+ protected def isHidden(d: Diagnostic)(implicit ctx: Context) = d.promotedSeverity match {
case VerboseINFO => !ctx.settings.verbose.value
case DeprecationWARNING | UncheckedWARNING | FeatureWARNING => true
case _ => false
}
- private def enablingOption(warning: Severity)(implicit ctx: Context) = warning match {
- case DeprecationWARNING => ctx.settings.deprecation
- case UncheckedWARNING => ctx.settings.unchecked
- case FeatureWARNING => ctx.settings.feature
- }
-
- private def promoteSeverity(s: Severity)(implicit ctx: Context): Severity =
- if (isConditionalWarning(s) && enablingOption(s).value) WARNING else s
-
val count = new Array[Int](ERROR.level + 1)
- def report(d: Diagnostic)(implicit ctx: Context): Unit = {
- val severity = promoteSeverity(d.severity)
- if (!isHidden(severity, d.pos)) doReport(d)
- count(severity.level) += 1
- }
+ def report(d: Diagnostic)(implicit ctx: Context): Unit =
+ if (!isHidden(d)) {
+ doReport(d)
+ count(d.promotedSeverity.level) += 1
+ }
def incomplete(d: Diagnostic)(implicit ctx: Context): Unit =
incompleteHandler(d)(ctx)
diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
index b14b842d0..93e24b27f 100644
--- a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
+++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
@@ -4,7 +4,7 @@ package reporting
import scala.collection.mutable
import util.{SourcePosition, SourceFile}
-import Reporter.Severity
+import Reporter.{Severity, Diagnostic}
import core.Contexts.Context
/**
@@ -18,12 +18,12 @@ trait UniqueMessagePositions extends Reporter {
/** Logs a position and returns true if it was already logged.
* @note Two positions are considered identical for logging if they have the same point.
*/
- override def isHidden(severity: Severity, pos: SourcePosition)(implicit ctx: Context): Boolean =
- super.isHidden(severity, pos) || {
- pos.exists && {
- positions get (ctx.source, pos.point) match {
- case Some(s) if s.level >= severity.level => true
- case _ => positions((ctx.source, pos.point)) = severity; false
+ override def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean =
+ super.isHidden(d) || {
+ d.pos.exists && {
+ positions get (ctx.source, d.pos.point) match {
+ case Some(s) if s.level >= d.severity.level => true
+ case _ => positions((ctx.source, d.pos.point)) = d.severity; false
}
}
}
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 7a91adde6..bf2d19e85 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -5,9 +5,11 @@ package typer
import ast._
import core._
import Trees._
-import Types._, Contexts._, Decorators._, Denotations._
+import Types._, Contexts._, Decorators._, Denotations._, Symbols._
import Applications._
import util.Positions._
+import printing.Showable
+import reporting.Reporter.SuppressedMessage
object ErrorReporting {
@@ -27,11 +29,11 @@ object ErrorReporting {
case tp: FunProtoType =>
val result = tp.resultType match {
case tp: WildcardType => ""
- case tp => s"and expected result type $tp"
+ case tp => i"and expected result type $tp"
}
- s"arguments (${tp.typedArgs map (_.tpe.show) mkString ", "})$result"
+ i"arguments (${tp.typedArgs.tpes}%, %)$result"
case _ =>
- s"expected type ${tp.show}"
+ i"expected type $tp"
}
def anonymousTypeMemberStr(tpe: Type) = {
@@ -40,12 +42,12 @@ object ErrorReporting {
case _: PolyType | _: MethodType => "method"
case _ => "value of type"
}
- s"$kind $tpe"
+ i"$kind $tpe"
}
def overloadedAltsStr(alts: List[SingleDenotation]) =
- s"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
- s" ${alts map (_.info) mkString "\n "}"
+ i"overloaded alternatives of ${denotStr(alts.head)} with types\n" +
+ i" ${alts map (_.info)}%\n %"
def denotStr(denot: Denotation): String =
if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
@@ -61,13 +63,46 @@ object ErrorReporting {
def patternConstrStr(tree: Tree): String = ???
- def typeMismatch(tree: Tree, pt: Type): Tree =
- errorTree(tree,
- s"""type mismatch:
- | found : ${tree.tpe.show}
- | required: ${pt.show}""".stripMargin)
+ def typeMismatch(tree: Tree, pt: Type): Tree = {
+ val result = errorTree(tree,
+ i"""type mismatch:
+ | found : ${tree.tpe}
+ | required: $pt""".stripMargin)
+ if (ctx.settings.explaintypes.value)
+ new ExplainingTypeComparer().isSubType(tree.tpe, pt)
+ result
+ }
}
def err(implicit ctx: Context): Errors = new Errors
+
+ def isSensical(arg: Any)(implicit ctx: Context): Boolean = arg match {
+ case tpe: Type if tpe.isErroneous => false
+ case NoSymbol => false
+ case _ => true
+ }
+
+ def treatArg(arg: Any, suffix: String)(implicit ctx: Context): (Any, String) = arg match {
+ case arg: Showable =>
+ (arg.show, suffix)
+ case arg: List[_] if suffix.head == '%' =>
+ val (sep, rest) = suffix.tail.span(_ != '%')
+ if (rest.nonEmpty) (arg mkString sep, rest.tail)
+ else (arg, suffix)
+ case _ =>
+ (arg, suffix)
+ }
+
+ /** Implementation of i"..." string interpolator */
+ implicit class InfoString(val sc: StringContext) extends AnyVal {
+
+ def i(args: Any*)(implicit ctx: Context): String = {
+ if (ctx.reporter.hasErrors && ctx.suppressNonSensicalErrors && !args.forall(isSensical(_)))
+ throw new SuppressedMessage
+ val prefix :: suffixes = sc.parts.toList
+ val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
+ new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
+ }
+ }
} \ No newline at end of file