aboutsummaryrefslogtreecommitdiff
path: root/compiler/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-11-04 16:44:06 +0100
committerMartin Odersky <odersky@gmail.com>2016-11-24 16:54:24 +0100
commite6e47f195d5985b07934cdedb22680f767a6ecb5 (patch)
tree497668342691dd71dd740ab07ad8efb142f7d1e7 /compiler/src
parent3588832eb3c45b151d78e66b5cde1f4e772d52a8 (diff)
downloaddotty-e6e47f195d5985b07934cdedb22680f767a6ecb5.tar.gz
dotty-e6e47f195d5985b07934cdedb22680f767a6ecb5.tar.bz2
dotty-e6e47f195d5985b07934cdedb22680f767a6ecb5.zip
Better reporting of nested implicit failures
Error messages of nested implicit failures are now reported with the top-level message if -explaintypes is set.
Diffstat (limited to 'compiler/src')
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/Reporter.scala9
-rw-r--r--compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Implicits.scala45
3 files changed, 47 insertions, 15 deletions
diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
index 8477cfe28..26c1e5ebc 100644
--- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -286,11 +286,16 @@ abstract class Reporter extends interfaces.ReporterResult {
}
/** Should this diagnostic not be reported at all? */
- def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean = ctx.mode.is(Mode.Printing)
+ def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean =
+ ctx.mode.is(Mode.Printing)
/** Does this reporter contain not yet reported errors or warnings? */
def hasPending: Boolean = false
+ /** If this reporter buffers messages, remove and return all buffered messages. */
+ def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] = Nil
+
/** Issue all error messages in this reporter to next outer one, or make sure they are written. */
- def flush()(implicit ctx: Context): Unit = {}
+ def flush()(implicit ctx: Context): Unit =
+ removeBufferedMessages.foreach(ctx.reporter.report)
}
diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
index 586273c2e..34b109882 100644
--- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala
@@ -36,11 +36,9 @@ class StoreReporter(outer: Reporter) extends Reporter {
}
}
- override def flush()(implicit ctx: Context) =
- if (infos != null) {
- infos.foreach(ctx.reporter.report(_))
- infos = null
- }
+ override def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] =
+ if (infos != null) try infos.toList finally infos = null
+ else Nil
override def errorsReported = hasErrors || outer.errorsReported
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
index f3dceea71..9bd6e6c45 100644
--- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala
@@ -24,6 +24,7 @@ import Constants._
import Applications._
import ProtoTypes._
import ErrorReporting._
+import reporting.diagnostic.MessageContainer
import Inferencing.fullyDefinedType
import Trees._
import Hashable._
@@ -212,6 +213,8 @@ object Implicits {
/** A "no matching implicit found" failure */
case object NoImplicitMatches extends SearchFailure
+ case object DivergingImplicit extends SearchFailure
+
/** A search failure that can show information about the cause */
abstract class ExplainedSearchFailure extends SearchFailure {
protected def pt: Type
@@ -233,9 +236,35 @@ object Implicits {
"\n " + explanation
}
- class NonMatchingImplicit(ref: TermRef, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
- def explanation(implicit ctx: Context): String =
- em"${err.refStr(ref)} does not $qualify"
+ class NonMatchingImplicit(ref: TermRef,
+ val pt: Type,
+ val argument: tpd.Tree,
+ trail: List[MessageContainer]) extends ExplainedSearchFailure {
+ private val separator = "\n**** because ****\n"
+
+ /** Replace repeated parts beginning with `separator` by ... */
+ private def elideRepeated(str: String): String = {
+ val startIdx = str.indexOfSlice(separator)
+ val nextIdx = str.indexOfSlice(separator, startIdx + separator.length)
+ if (nextIdx < 0) str
+ else {
+ val prefix = str.take(startIdx)
+ val first = str.slice(startIdx, nextIdx)
+ var rest = str.drop(nextIdx)
+ if (rest.startsWith(first)) {
+ rest = rest.drop(first.length)
+ val dots = "\n\n ...\n"
+ if (!rest.startsWith(dots)) rest = dots ++ rest
+ }
+ prefix ++ first ++ rest
+ }
+ }
+
+ def explanation(implicit ctx: Context): String = {
+ val headMsg = em"${err.refStr(ref)} does not $qualify"
+ val trailMsg = trail.map(mc => i"$separator ${mc.message}").mkString
+ elideRepeated(headMsg ++ trailMsg)
+ }
}
class ShadowedImplicit(ref: TermRef, shadowing: Type, val pt: Type, val argument: tpd.Tree) extends ExplainedSearchFailure {
@@ -587,7 +616,7 @@ trait Implicits { self: Typer =>
val wildProto = implicitProto(pt, wildApprox(_))
/** Search failures; overridden in ExplainedImplicitSearch */
- protected def nonMatchingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches
+ protected def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]): SearchFailure = NoImplicitMatches
protected def divergingImplicit(ref: TermRef): SearchFailure = NoImplicitMatches
protected def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure = NoImplicitMatches
protected def failedSearch: SearchFailure = NoImplicitMatches
@@ -628,7 +657,7 @@ trait Implicits { self: Typer =>
{ implicits.println(i"invalid eqAny[$tp1, $tp2]"); false }
}
if (ctx.reporter.hasErrors)
- nonMatchingImplicit(ref)
+ nonMatchingImplicit(ref, ctx.reporter.removeBufferedMessages)
else if (contextual && !ctx.mode.is(Mode.ImplicitShadowing) &&
!shadowing.tpe.isError && !refMatches(shadowing)) {
implicits.println(i"SHADOWING $ref in ${ref.termSymbol.owner} is shadowed by $shadowing in ${shadowing.symbol.owner}")
@@ -637,7 +666,7 @@ trait Implicits { self: Typer =>
else generated1 match {
case TypeApply(fn, targs @ (arg1 :: arg2 :: Nil))
if fn.symbol == defn.Predef_eqAny && !validEqAnyArgs(arg1.tpe, arg2.tpe) =>
- nonMatchingImplicit(ref)
+ nonMatchingImplicit(ref, Nil)
case _ =>
SearchSuccess(generated1, ref, ctx.typerState)
}
@@ -743,8 +772,8 @@ trait Implicits { self: Typer =>
fail
}
def failures = myFailures.toList
- override def nonMatchingImplicit(ref: TermRef) =
- record(new NonMatchingImplicit(ref, pt, argument))
+ override def nonMatchingImplicit(ref: TermRef, trail: List[MessageContainer]) =
+ record(new NonMatchingImplicit(ref, pt, argument, trail))
override def divergingImplicit(ref: TermRef) =
record(new DivergingImplicit(ref, pt, argument))
override def shadowedImplicit(ref: TermRef, shadowing: Type): SearchFailure =