@@ -278,7 +278,11 @@ object Implicits {
278
278
/** A "no matching implicit found" failure */
279
279
case object NoImplicitMatches extends SearchFailure
280
280
281
- case object DivergingImplicit extends SearchFailure
281
+ /** A tree representing a failed search for an implicit argument */
282
+ case class FailedSearch (failure : SearchFailure , errorFn : String => String ) extends WithoutTypeOrPos [Type ] {
283
+ override def tag = - 1
284
+ override def isEmpty = true
285
+ }
282
286
283
287
/** A search failure that can show information about the cause */
284
288
abstract class ExplainedSearchFailure extends SearchFailure {
@@ -552,7 +556,7 @@ trait Implicits { self: Typer =>
552
556
* which is itself parameterized by another string,
553
557
* indicating where the implicit parameter is needed
554
558
*/
555
- def inferImplicitArg (formal : Type , error : ( String => String ) => Unit , pos : Position )(implicit ctx : Context ): Tree = {
559
+ def inferImplicitArg (formal : Type , pos : Position )(implicit ctx : Context ): Tree = {
556
560
557
561
/** If `formal` is of the form ClassTag[T], where `T` is a class type,
558
562
* synthesize a class tag for `T`.
@@ -562,16 +566,18 @@ trait Implicits { self: Typer =>
562
566
case arg :: Nil =>
563
567
fullyDefinedType(arg, " ClassTag argument" , pos) match {
564
568
case defn.ArrayOf (elemTp) =>
565
- val etag = inferImplicitArg(defn.ClassTagType .appliedTo(elemTp), error, pos)
569
+ val etag = inferImplicitArg(defn.ClassTagType .appliedTo(elemTp), pos)
566
570
if (etag.isEmpty) etag else etag.select(nme.wrap)
567
571
case tp if hasStableErasure(tp) =>
568
572
if (defn.isBottomClass(tp.typeSymbol))
569
- error(where => i " attempt to take ClassTag of undetermined type for $where" )
570
- ref(defn.ClassTagModule )
571
- .select(nme.apply)
572
- .appliedToType(tp)
573
- .appliedTo(clsOf(erasure(tp)))
574
- .withPos(pos)
573
+ FailedSearch (NoImplicitMatches ,
574
+ where => i " attempt to take ClassTag of undetermined type for $where" )
575
+ else
576
+ ref(defn.ClassTagModule )
577
+ .select(nme.apply)
578
+ .appliedToType(tp)
579
+ .appliedTo(clsOf(erasure(tp)))
580
+ .withPos(pos)
575
581
case tp =>
576
582
EmptyTree
577
583
}
@@ -635,17 +641,16 @@ trait Implicits { self: Typer =>
635
641
else
636
642
arg
637
643
case ambi : AmbiguousImplicits =>
638
- error(where => s " ambiguous implicits: ${ambi.explanation} of $where" )
639
- EmptyTree
644
+ FailedSearch (ambi, where => s " ambiguous implicits: ${ambi.explanation} of $where" )
640
645
case failure : SearchFailure =>
641
- val arg =
646
+ val fallbackArg =
642
647
if (formalValue.isRef(defn.ClassTagClass ))
643
648
synthesizedClassTag(formalValue)
644
649
else if (formalValue.isRef(defn.EqClass ))
645
650
synthesizedEq(formalValue)
646
651
else
647
652
EmptyTree
648
- if (! arg .isEmpty) arg
653
+ if (! fallbackArg .isEmpty) fallbackArg
649
654
else {
650
655
var msgFn = (where : String ) =>
651
656
em " no implicit argument of type $formal found for $where" + failure.postscript
@@ -659,12 +664,21 @@ trait Implicits { self: Typer =>
659
664
formalValue.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
660
665
formalValue.argInfos)
661
666
}
662
- error(msgFn)
663
- EmptyTree
667
+ FailedSearch (failure, msgFn)
664
668
}
665
669
}
666
670
}
667
671
672
+ /** Search an implicit argument and report error if not found */
673
+ def implicitArgTree (formal : Type , pos : Position , where : String = " " )(implicit ctx : Context ): Tree =
674
+ inferImplicitArg(formal, pos) match {
675
+ case FailedSearch (fail, errorFn) =>
676
+ ctx.error(errorFn(where), pos)
677
+ EmptyTree
678
+ case tree =>
679
+ tree
680
+ }
681
+
668
682
private def assumedCanEqual (ltp : Type , rtp : Type )(implicit ctx : Context ) = {
669
683
def eqNullable : Boolean = {
670
684
val other =
@@ -694,8 +708,7 @@ trait Implicits { self: Typer =>
694
708
/** Check that equality tests between types `ltp` and `rtp` make sense */
695
709
def checkCanEqual (ltp : Type , rtp : Type , pos : Position )(implicit ctx : Context ): Unit =
696
710
if (! ctx.isAfterTyper && ! assumedCanEqual(ltp, rtp)) {
697
- val res = inferImplicitArg(
698
- defn.EqType .appliedTo(ltp, rtp), msgFun => ctx.error(msgFun(" " ), pos), pos)
711
+ val res = implicitArgTree(defn.EqType .appliedTo(ltp, rtp), pos)
699
712
implicits.println(i " Eq witness found for $ltp / $rtp: $res: ${res.tpe}" )
700
713
}
701
714
@@ -771,7 +784,10 @@ trait Implicits { self: Typer =>
771
784
772
785
/** Search failures; overridden in ExplainedImplicitSearch */
773
786
protected def nonMatchingImplicit (ref : TermRef , trail : List [MessageContainer ]): SearchFailure = NoImplicitMatches
774
- protected def divergingImplicit (ref : TermRef ): SearchFailure = NoImplicitMatches
787
+ protected def divergingImplicit (ref : TermRef ): SearchFailure = {
788
+ implicits.println(i " diverging implicit: $ref for $pt, search history = ${ctx.searchHistory}" )
789
+ new DivergingImplicit (ref, pt, argument)
790
+ }
775
791
protected def shadowedImplicit (ref : TermRef , shadowing : Type ): SearchFailure = NoImplicitMatches
776
792
protected def failedSearch : SearchFailure = NoImplicitMatches
777
793
@@ -802,11 +818,16 @@ trait Implicits { self: Typer =>
802
818
}
803
819
}
804
820
805
- if (ctx.reporter.hasErrors)
806
- nonMatchingImplicit(ref, ctx.reporter.removeBufferedMessages)
821
+ if (ctx.reporter.hasErrors) {
822
+ val trail = ctx.reporter.removeBufferedMessages
823
+ generated1 match {
824
+ case failed : FailedSearch => failed.failure
825
+ case _ => nonMatchingImplicit(ref, trail)
826
+ }
827
+ }
807
828
else if (contextual && ! ctx.mode.is(Mode .ImplicitShadowing ) &&
808
829
! shadowing.tpe.isError && ! refSameAs(shadowing)) {
809
- implicits.println(i " SHADOWING $ref in ${ref.termSymbol.owner } is shadowed by $shadowing in ${shadowing.symbol.owner }" )
830
+ implicits.println(i " SHADOWING $ref in ${ref.termSymbol.maybeOwner } is shadowed by $shadowing in ${shadowing.symbol.maybeOwner }" )
810
831
shadowedImplicit(ref, methPart(shadowing).tpe)
811
832
}
812
833
else
@@ -815,28 +836,38 @@ trait Implicits { self: Typer =>
815
836
816
837
/** Given a list of implicit references, produce a list of all implicit search successes,
817
838
* where the first is supposed to be the best one.
839
+ * Except if one of the results is a diverging implicit, produce a list consisting
840
+ * of just that result.
818
841
* @param pending The list of implicit references that remain to be investigated
819
842
* @param acc An accumulator of successful matches found so far.
820
843
*/
821
- def rankImplicits (pending : List [Candidate ], acc : List [SearchSuccess ]): List [SearchSuccess ] = pending match {
822
- case cand :: pending1 =>
823
- val history = ctx.searchHistory nest wildProto
824
- val result =
825
- if (history eq ctx.searchHistory) divergingImplicit(cand.ref)
826
- else typedImplicit(cand)(nestedContext.setNewTyperState().setSearchHistory(history))
827
- result match {
828
- case fail : SearchFailure =>
829
- rankImplicits(pending1, acc)
830
- case best : SearchSuccess =>
831
- if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent) best :: Nil
832
- else {
833
- val newPending = pending1.filter(cand1 =>
834
- ctx.typerState.test(isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext)))
835
- rankImplicits(newPending, best :: acc)
836
- }
837
- }
838
- case nil => acc
839
- }
844
+ def rankImplicits (pending : List [Candidate ],
845
+ successes : List [SearchSuccess ],
846
+ failures : mutable.ListBuffer [SearchFailure ]): (List [SearchSuccess ], List [SearchFailure ]) =
847
+ pending match {
848
+ case cand :: pending1 =>
849
+ val history = ctx.searchHistory nest wildProto
850
+ val result =
851
+ if (history eq ctx.searchHistory) divergingImplicit(cand.ref)
852
+ else typedImplicit(cand)(nestedContext.setNewTyperState().setSearchHistory(history))
853
+ result match {
854
+ case fail : AmbiguousImplicits =>
855
+ (Nil , fail :: Nil )
856
+ case fail : SearchFailure =>
857
+ rankImplicits(pending1, successes,
858
+ if (fail.isInstanceOf [DivergingImplicit ]) fail +=: failures
859
+ else failures += fail)
860
+ case best : SearchSuccess =>
861
+ if (ctx.mode.is(Mode .ImplicitExploration ) || isCoherent)
862
+ (best :: Nil , failures.toList)
863
+ else {
864
+ val newPending = pending1.filter(cand1 =>
865
+ ctx.typerState.test(isAsGood(cand1.ref, best.ref, cand1.level, best.level)(nestedContext)))
866
+ rankImplicits(newPending, best :: successes, failures)
867
+ }
868
+ }
869
+ case nil => (successes, failures.toList)
870
+ }
840
871
841
872
/** If the (result types of) the expected type, and both alternatives
842
873
* are all numeric value types, return the alternative which has
@@ -858,26 +889,28 @@ trait Implicits { self: Typer =>
858
889
}
859
890
860
891
/** Convert a (possibly empty) list of search successes into a single search result */
861
- def condense (hits : List [SearchSuccess ]): SearchResult = hits match {
862
- case best :: alts =>
892
+ def condense (successes : List [SearchSuccess ], failures : List [ SearchFailure ] ): SearchResult = successes match {
893
+ case ( best : SearchSuccess ) :: ( alts : List [ SearchSuccess ] @ unchecked) =>
863
894
alts.find(alt =>
864
895
ctx.typerState.test(isAsGood(alt.ref, best.ref, alt.level, best.level))) match {
865
- case Some (alt) =>
866
- typr.println(i " ambiguous implicits for $pt: ${best.ref} @ ${best.level}, ${alt.ref} @ ${alt.level}" )
867
- /* !!! DEBUG
868
- println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
869
- isAsGood(best.ref, alt.ref, explain = true)(ctx.fresh.withExploreTyperState)
870
- */
871
- numericValueTieBreak(best, alt) match {
872
- case eliminated : SearchSuccess => condense(hits.filter(_ ne eliminated))
873
- case _ => new AmbiguousImplicits (best.ref, alt.ref, pt, argument)
874
- }
875
- case None =>
876
- ctx.runInfo.useCount(best.ref) += 1
877
- best
878
- }
896
+ case Some (alt) =>
897
+ implicits.println(i " ambiguous implicits for $pt: ${best.ref} @ ${best.level}, ${alt.ref} @ ${alt.level}" )
898
+ /* !!! DEBUG
899
+ println(i"ambiguous refs: ${hits map (_.ref) map (_.show) mkString ", "}")
900
+ isAsGood(best.ref, alt.ref, explain = true)(ctx.fresh.withExploreTyperState)
901
+ */
902
+ numericValueTieBreak(best, alt) match {
903
+ case eliminated : SearchSuccess =>
904
+ condense(successes.filter(_ ne eliminated), failures)
905
+ case _ =>
906
+ new AmbiguousImplicits (best.ref, alt.ref, pt, argument)
907
+ }
908
+ case None =>
909
+ ctx.runInfo.useCount(best.ref) += 1
910
+ best
911
+ }
879
912
case Nil =>
880
- failedSearch
913
+ failures.headOption.getOrElse( NoImplicitMatches )
881
914
}
882
915
883
916
def ranking (cand : Candidate ) = - ctx.runInfo.useCount(cand.ref)
@@ -894,7 +927,8 @@ trait Implicits { self: Typer =>
894
927
case _ => eligible.sortBy(ranking)
895
928
}
896
929
897
- condense(rankImplicits(sort(eligible), Nil ))
930
+ val (successes, failures) = rankImplicits(sort(eligible), Nil , new mutable.ListBuffer )
931
+ condense(successes, failures)
898
932
}
899
933
900
934
/** Find a unique best implicit reference */
@@ -905,6 +939,7 @@ trait Implicits { self: Typer =>
905
939
searchImplicits(eligible, contextual) match {
906
940
case result : SearchSuccess => result
907
941
case result : AmbiguousImplicits => result
942
+ case result : DivergingImplicit => result
908
943
case result : SearchFailure =>
909
944
if (contextual) bestImplicit(contextual = false ) else result
910
945
}
@@ -994,6 +1029,8 @@ class SearchHistory(val searchDepth: Int, val seen: Map[ClassSymbol, Int]) {
994
1029
else updateMap(proto.classSymbols, seen)
995
1030
}
996
1031
}
1032
+
1033
+ override def toString = s " SearchHistory(depth = $searchDepth, seen = $seen) "
997
1034
}
998
1035
999
1036
/** A set of term references where equality is =:= */
0 commit comments