summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-03-31 11:43:35 +0200
committerAdriaan Moors <adriaan.moors@typesafe.com>2014-03-31 10:33:09 -0700
commit5e795fc8bb53a016d0dff4127d83df4192f1cc13 (patch)
treed4b79e944e769a34eb6c0a9bffd3a99393027b64 /src
parenta5728ed41639c1791c2ad06a0a99295950ee49af (diff)
downloadscala-5e795fc8bb53a016d0dff4127d83df4192f1cc13.tar.gz
scala-5e795fc8bb53a016d0dff4127d83df4192f1cc13.tar.bz2
scala-5e795fc8bb53a016d0dff4127d83df4192f1cc13.zip
Refactor handling of failures in implicit search
Better encapsulation for `DivergentImplicitRecovery` by replacing the vars `countDown` and `implicitSym` with a single var holding `Option[DivergentImplicitTypeError]`. Also adds a pending test for SI-8460 that will be addressed in the next commit. This commit is just groundwork and should not change any results of implicit search.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala42
1 files changed, 24 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 1a38fcf3a4..a777f483e5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -833,19 +833,26 @@ trait Implicits {
* so that if there is a best candidate it can still be selected.
*/
object DivergentImplicitRecovery {
- // symbol of the implicit that caused the divergence.
- // Initially null, will be saved on first diverging expansion.
- private var implicitSym: Symbol = _
- private var countdown: Int = 1
-
- def sym: Symbol = implicitSym
- def apply(search: SearchResult, i: ImplicitInfo): SearchResult =
- if (search.isDivergent && countdown > 0) {
- countdown -= 1
- implicitSym = i.sym
- log(s"discarding divergent implicit $implicitSym during implicit search")
+ private var divergentError: Option[DivergentImplicitTypeError] = None
+
+ private def saveDivergent(err: DivergentImplicitTypeError) {
+ if (divergentError.isEmpty) divergentError = Some(err)
+ }
+
+ def issueSavedDivergentError() {
+ divergentError foreach (err => context.issue(err))
+ }
+
+ def apply(search: SearchResult, i: ImplicitInfo, errors: Seq[AbsTypeError]): SearchResult = {
+ if (search.isDivergent && divergentError.isEmpty) {
+ // Divergence triggered by `i` at this level of the implicit serach. We haven't
+ // seen divergence so far, we won't issue this error just yet, and instead temporarily
+ // treat `i` as a failed candidate.
+ saveDivergent(DivergentImplicitTypeError(tree, pt, i.sym))
+ log(s"discarding divergent implicit ${i.sym} during implicit search")
SearchFailure
} else search
+ }
}
/** Sorted list of eligible implicits.
@@ -871,7 +878,9 @@ trait Implicits {
@tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match {
case Nil => acc
case i :: is =>
- DivergentImplicitRecovery(typedImplicit(i, ptChecked = true, isLocalToCallsite), i) match {
+ val typedImplicitResult = typedImplicit(i, ptChecked = true, isLocalToCallsite)
+ val recoveredResult = DivergentImplicitRecovery(typedImplicitResult, i, context.errors)
+ recoveredResult match {
case sr if sr.isDivergent =>
Nil
case sr if sr.isFailure =>
@@ -921,12 +930,9 @@ trait Implicits {
}
if (best.isFailure) {
- /* If there is no winner, and we witnessed and caught divergence,
- * now we can throw it for the error message.
- */
- if (DivergentImplicitRecovery.sym != null) {
- DivergingImplicitExpansionError(tree, pt, DivergentImplicitRecovery.sym)(context)
- }
+ // If there is no winner, and we witnessed and recorded a divergence error,
+ // our recovery attempt has failed, so we must now issue it.
+ DivergentImplicitRecovery.issueSavedDivergentError()
if (invalidImplicits.nonEmpty)
setAddendum(pos, () =>