diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-03-31 11:43:35 +0200 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2014-03-31 10:33:09 -0700 |
commit | 5e795fc8bb53a016d0dff4127d83df4192f1cc13 (patch) | |
tree | d4b79e944e769a34eb6c0a9bffd3a99393027b64 /src | |
parent | a5728ed41639c1791c2ad06a0a99295950ee49af (diff) | |
download | scala-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.scala | 42 |
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, () => |