diff options
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 |