@@ -489,6 +489,11 @@ object Implicits:
489
489
@ sharable val NoMatchingImplicitsFailure : SearchFailure =
490
490
SearchFailure (NoMatchingImplicits , NoSpan )(using NoContext )
491
491
492
+ @ sharable object ImplicitSearchTooLarge extends NoMatchingImplicits (NoType , EmptyTree , OrderingConstraint .empty)
493
+
494
+ @ sharable val ImplicitSearchTooLargeFailure : SearchFailure =
495
+ SearchFailure (ImplicitSearchTooLarge , NoSpan )(using NoContext )
496
+
492
497
/** An ambiguous implicits failure */
493
498
class AmbiguousImplicits (val alt1 : SearchSuccess , val alt2 : SearchSuccess , val expectedType : Type , val argument : Tree ) extends SearchFailureType {
494
499
def explanation (using Context ): String =
@@ -790,16 +795,8 @@ trait Implicits:
790
795
*/
791
796
def inferView (from : Tree , to : Type )(using Context ): SearchResult = {
792
797
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
803
800
else {
804
801
def adjust (to : Type ) = to.stripTypeVar.widenExpr match {
805
802
case SelectionProto (name, memberProto, compat, true ) =>
@@ -1129,18 +1126,36 @@ trait Implicits:
1129
1126
1130
1127
val isNotGiven : Boolean = wildProto.classSymbol == defn.NotGivenClass
1131
1128
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
+
1132
1145
/** Try to type-check implicit reference, after checking that this is not
1133
1146
* a diverging search
1134
1147
*/
1135
1148
def tryImplicit (cand : Candidate , contextual : Boolean ): SearchResult =
1136
1149
if checkDivergence(cand) then
1137
1150
SearchFailure (new DivergingImplicit (cand.ref, wideProto, argument), span)
1138
- else {
1151
+ else if searchTooLarge() then
1152
+ ImplicitSearchTooLargeFailure
1153
+ else
1139
1154
val history = ctx.searchHistory.nest(cand, pt)
1140
1155
val typingCtx =
1141
1156
nestedContext().setNewTyperState().setFreshGADTBounds.setSearchHistory(history)
1142
1157
val result = typedImplicit(cand, pt, argument, span)(using typingCtx)
1143
- result match {
1158
+ result match
1144
1159
case res : SearchSuccess =>
1145
1160
ctx.searchHistory.defineBynameImplicit(wideProto, res)
1146
1161
case _ =>
@@ -1152,8 +1167,6 @@ trait Implicits:
1152
1167
// tests/neg/implicitSearch.check
1153
1168
typingCtx.typerState.gc()
1154
1169
result
1155
- }
1156
- }
1157
1170
1158
1171
/** Search a list of eligible implicit references */
1159
1172
private def searchImplicit (eligible : List [Candidate ], contextual : Boolean ): SearchResult =
@@ -1242,7 +1255,9 @@ trait Implicits:
1242
1255
1243
1256
negateIfNot(tryImplicit(cand, contextual)) match {
1244
1257
case fail : SearchFailure =>
1245
- if (fail.isAmbiguous)
1258
+ if fail eq ImplicitSearchTooLargeFailure then
1259
+ fail
1260
+ else if (fail.isAmbiguous)
1246
1261
if migrateTo3 then
1247
1262
val result = rank(remaining, found, NoMatchingImplicitsFailure :: rfailures)
1248
1263
if (result.isSuccess)
@@ -1411,27 +1426,43 @@ trait Implicits:
1411
1426
rank(sort(eligible), NoMatchingImplicitsFailure , Nil )
1412
1427
end searchImplicit
1413
1428
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
+
1414
1442
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
1435
1466
end searchImplicit
1436
1467
1437
1468
/** Find a unique best implicit reference */
@@ -1610,13 +1641,17 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con
1610
1641
end OpenSearch
1611
1642
1612
1643
/**
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.
1614
1645
*/
1615
1646
final class SearchRoot extends SearchHistory :
1616
1647
val root = this
1617
1648
val byname = false
1618
1649
def openSearchPairs = Nil
1619
1650
1651
+ /** How many expressions were constructed so far in the current toplevel implicit search?
1652
+ */
1653
+ var nestedSearches : Int = 0
1654
+
1620
1655
/** The dictionary of recursive implicit types and corresponding terms for this search. */
1621
1656
var myImplicitDictionary : mutable.Map [Type , (TermRef , tpd.Tree )] = null
1622
1657
private def implicitDictionary =
0 commit comments