@@ -489,6 +489,11 @@ object Implicits:
489489 @ sharable val NoMatchingImplicitsFailure : SearchFailure =
490490 SearchFailure (NoMatchingImplicits , NoSpan )(using NoContext )
491491
492+ @ sharable object ImplicitSearchTooLarge extends NoMatchingImplicits (NoType , EmptyTree , OrderingConstraint .empty)
493+
494+ @ sharable val ImplicitSearchTooLargeFailure : SearchFailure =
495+ SearchFailure (ImplicitSearchTooLarge , NoSpan )(using NoContext )
496+
492497 /** An ambiguous implicits failure */
493498 class AmbiguousImplicits (val alt1 : SearchSuccess , val alt2 : SearchSuccess , val expectedType : Type , val argument : Tree ) extends SearchFailureType {
494499 def explanation (using Context ): String =
@@ -790,16 +795,8 @@ trait Implicits:
790795 */
791796 def inferView (from : Tree , to : Type )(using Context ): SearchResult = {
792797 record(" inferView" )
793- val wfromtp = from.tpe.widen
794- if to.isAny
795- || to.isAnyRef
796- || to.isRef(defn.UnitClass )
797- || wfromtp.isRef(defn.NothingClass )
798- || wfromtp.isRef(defn.NullClass )
799- || ! ctx.mode.is(Mode .ImplicitsEnabled )
800- || from.isInstanceOf [Super ]
801- || (wfromtp eq NoPrefix )
802- then NoMatchingImplicitsFailure
798+ if ! ctx.mode.is(Mode .ImplicitsEnabled ) || from.isInstanceOf [Super ] then
799+ NoMatchingImplicitsFailure
803800 else {
804801 def adjust (to : Type ) = to.stripTypeVar.widenExpr match {
805802 case SelectionProto (name, memberProto, compat, true ) =>
@@ -1129,18 +1126,36 @@ trait Implicits:
11291126
11301127 val isNotGiven : Boolean = wildProto.classSymbol == defn.NotGivenClass
11311128
1129+ private def searchTooLarge (): Boolean = ctx.searchHistory match
1130+ case root : SearchRoot =>
1131+ root.nestedSearches = 1
1132+ false
1133+ case h =>
1134+ val limit = ctx.settings.XimplicitSearchLimit .value
1135+ val nestedSearches = h.root.nestedSearches
1136+ val result = nestedSearches > limit
1137+ if result then
1138+ var c = ctx
1139+ while c.outer.typer eq ctx.typer do c = c.outer
1140+ report.warning(ImplicitSearchTooLargeWarning (limit, h.openSearchPairs), ctx.source.atSpan(span))(using c)
1141+ else
1142+ h.root.nestedSearches = nestedSearches + 1
1143+ result
1144+
11321145 /** Try to type-check implicit reference, after checking that this is not
11331146 * a diverging search
11341147 */
11351148 def tryImplicit (cand : Candidate , contextual : Boolean ): SearchResult =
11361149 if checkDivergence(cand) then
11371150 SearchFailure (new DivergingImplicit (cand.ref, wideProto, argument), span)
1138- else {
1151+ else if searchTooLarge() then
1152+ ImplicitSearchTooLargeFailure
1153+ else
11391154 val history = ctx.searchHistory.nest(cand, pt)
11401155 val typingCtx =
11411156 nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history)
11421157 val result = typedImplicit(cand, pt, argument, span)(using typingCtx)
1143- result match {
1158+ result match
11441159 case res : SearchSuccess =>
11451160 ctx.searchHistory.defineBynameImplicit(wideProto, res)
11461161 case _ =>
@@ -1152,8 +1167,6 @@ trait Implicits:
11521167 // tests/neg/implicitSearch.check
11531168 typingCtx.typerState.gc()
11541169 result
1155- }
1156- }
11571170
11581171 /** Search a list of eligible implicit references */
11591172 private def searchImplicit (eligible : List [Candidate ], contextual : Boolean ): SearchResult =
@@ -1242,7 +1255,9 @@ trait Implicits:
12421255
12431256 negateIfNot(tryImplicit(cand, contextual)) match {
12441257 case fail : SearchFailure =>
1245- if (fail.isAmbiguous)
1258+ if fail eq ImplicitSearchTooLargeFailure then
1259+ fail
1260+ else if (fail.isAmbiguous)
12461261 if migrateTo3 then
12471262 val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures)
12481263 if (result.isSuccess)
@@ -1411,27 +1426,43 @@ trait Implicits:
14111426 rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
14121427 end searchImplicit
14131428
1429+ def isUnderSpecifiedArgument (tp : Type ): Boolean =
1430+ tp.isRef(defn.NothingClass ) || tp.isRef(defn.NullClass ) || (tp eq NoPrefix )
1431+
1432+ private def isUnderspecified (tp : Type ): Boolean = tp.stripTypeVar match
1433+ case tp : WildcardType =>
1434+ ! tp.optBounds.exists || isUnderspecified(tp.optBounds.hiBound)
1435+ case tp : ViewProto =>
1436+ isUnderspecified(tp.resType)
1437+ || tp.resType.isRef(defn.UnitClass )
1438+ || isUnderSpecifiedArgument(tp.argType.widen)
1439+ case _ =>
1440+ tp.isAny || tp.isAnyRef
1441+
14141442 private def searchImplicit (contextual : Boolean ): SearchResult =
1415- val eligible =
1416- if contextual then ctx.implicits.eligible(wildProto)
1417- else implicitScope(wildProto).eligible
1418- searchImplicit(eligible, contextual) match
1419- case result : SearchSuccess =>
1420- result
1421- case failure : SearchFailure =>
1422- failure.reason match
1423- case _ : AmbiguousImplicits => failure
1424- case reason =>
1425- if contextual then
1426- searchImplicit(contextual = false ).recoverWith {
1427- failure2 => failure2.reason match
1428- case _ : AmbiguousImplicits => failure2
1429- case _ =>
1430- reason match
1431- case (_ : DivergingImplicit ) => failure
1432- case _ => List (failure, failure2).maxBy(_.tree.treeSize)
1433- }
1434- else failure
1443+ if isUnderspecified(wildProto) then
1444+ NoMatchingImplicitsFailure
1445+ else
1446+ val eligible =
1447+ if contextual then ctx.implicits.eligible(wildProto)
1448+ else implicitScope(wildProto).eligible
1449+ searchImplicit(eligible, contextual) match
1450+ case result : SearchSuccess =>
1451+ result
1452+ case failure : SearchFailure =>
1453+ failure.reason match
1454+ case _ : AmbiguousImplicits => failure
1455+ case reason =>
1456+ if contextual then
1457+ searchImplicit(contextual = false ).recoverWith {
1458+ failure2 => failure2.reason match
1459+ case _ : AmbiguousImplicits => failure2
1460+ case _ =>
1461+ reason match
1462+ case (_ : DivergingImplicit ) => failure
1463+ case _ => List (failure, failure2).maxBy(_.tree.treeSize)
1464+ }
1465+ else failure
14351466 end searchImplicit
14361467
14371468 /** Find a unique best implicit reference */
@@ -1610,13 +1641,17 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con
16101641end OpenSearch
16111642
16121643/**
1613- * The the state corresponding to the outermost context of an implicit searcch.
1644+ * The state corresponding to the outermost context of an implicit searcch.
16141645 */
16151646final class SearchRoot extends SearchHistory :
16161647 val root = this
16171648 val byname = false
16181649 def openSearchPairs = Nil
16191650
1651+ /** How many expressions were constructed so far in the current toplevel implicit search?
1652+ */
1653+ var nestedSearches : Int = 0
1654+
16201655 /** The dictionary of recursive implicit types and corresponding terms for this search. */
16211656 var myImplicitDictionary : mutable.Map [Type , (TermRef , tpd.Tree )] = null
16221657 private def implicitDictionary =
0 commit comments