Skip to content

Commit

Permalink
Refactor handling of failures in implicit search
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
retronym authored and adriaanm committed Mar 31, 2014
1 parent a5728ed commit 5e795fc
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
42 changes: 24 additions & 18 deletions src/compiler/scala/tools/nsc/typechecker/Implicits.scala
Expand Up @@ -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.
Expand All @@ -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 =>
Expand Down Expand Up @@ -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, () =>
Expand Down
25 changes: 25 additions & 0 deletions test/pending/pos/t8460.scala
@@ -0,0 +1,25 @@
object tan extends UFunc {
implicit def ImplDouble: Impl[Double, Double] = ???
}

trait UFunc {
trait TC[+A]
type Impl[V, VR] = UFunc.UImpl[this.type, V, VR]
}

object UFunc {
class UImpl[A, B, C]
implicit def implicitDoubleUTag[Tag, V, VR](implicit conv: V=>Double, impl: UImpl[Tag, Double, VR]):UImpl[Tag, V, VR] = ???

}

object Test {
implicitly[tan.Impl[Double, Double]]
// we should discard the one and only divergent implicit (`implicitDoubleUTag`)
// This is done under `scalac-hash v2.10.4 test.scala`, but not under
// `scalac-hash v2.10.4 -Xdivergence211 test.scala`
//
// This seems to be because the companion implicits contain redundant entries
//

}

0 comments on commit 5e795fc

Please sign in to comment.