Skip to content

Commit 24f7a9d

Browse files
committed
Optimize recursiveRef
1 parent b8e20de commit 24f7a9d

File tree

1 file changed

+26
-27
lines changed

1 file changed

+26
-27
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ trait Implicits:
13551355
* @param pt The target type for the above candidate.
13561356
* @result True if this candidate/pt are divergent, false otherwise.
13571357
*/
1358-
def checkDivergence(cand: Candidate)(using Context): Boolean =
1358+
def checkDivergence(cand: Candidate): Boolean =
13591359
// For full details of the algorithm see the SIP:
13601360
// https://docs.scala-lang.org/sips/byname-implicits.html
13611361
util.Stats.record("checkDivergence")
@@ -1374,7 +1374,6 @@ trait Implicits:
13741374
history match
13751375
case OpenSearch(cand1, tp, outer) =>
13761376
if cand1.ref eq cand.ref then
1377-
util.Stats.record("checkDivergence for sure")
13781377
val wideTp = tp.widenExpr
13791378
lazy val wildTp = wildApprox(wideTp)
13801379
lazy val tpSize = wideTp.typeSize
@@ -1409,30 +1408,28 @@ trait Implicits:
14091408
* @param pt The target type being searched for.
14101409
* @result The corresponding dictionary reference if any, NoType otherwise.
14111410
*/
1412-
def recursiveRef(using Context): Type =
1413-
val widePt = pt.widenExpr
1414-
1415-
ctx.searchHistory.refBynameImplicit(widePt).orElse {
1416-
val bynamePt = pt.isByName
1417-
if (!ctx.searchHistory.byname && !bynamePt) NoType // No recursion unless at least one open implicit is by name ...
1418-
else {
1419-
// We are able to tie a recursive knot if there is compatible term already under
1420-
// construction which is separated from this context by at least one by name
1421-
// argument as we ascend the chain of open implicits to the outermost search
1422-
// context.
1423-
@tailrec
1424-
def loop(history: SearchHistory, belowByname: Boolean): Type =
1425-
history match
1426-
case OpenSearch(cand, tp, outer) =>
1427-
if (belowByname || tp.isByName) && tp.widenExpr <:< widePt then tp
1428-
else loop(outer, belowByname || tp.isByName)
1429-
case _ => NoType
1430-
1431-
loop(ctx.searchHistory, bynamePt) match
1432-
case NoType => NoType
1433-
case tp => ctx.searchHistory.linkBynameImplicit(tp.widenExpr)
1434-
}
1435-
}
1411+
def recursiveRef: Type =
1412+
val found = ctx.searchHistory.refBynameImplicit(wideProto)
1413+
if found.exists then
1414+
found
1415+
else if !ctx.searchHistory.byname && !pt.isByName then
1416+
NoType // No recursion unless at least one open implicit is by name ...
1417+
else
1418+
// We are able to tie a recursive knot if there is compatible term already under
1419+
// construction which is separated from this context by at least one by name
1420+
// argument as we ascend the chain of open implicits to the outermost search
1421+
// context.
1422+
@tailrec
1423+
def loop(history: SearchHistory, belowByname: Boolean): Type =
1424+
history match
1425+
case OpenSearch(cand, tp, outer) =>
1426+
if (belowByname || tp.isByName) && tp.widenExpr <:< wideProto then tp
1427+
else loop(outer, belowByname || tp.isByName)
1428+
case _ => NoType
1429+
1430+
loop(ctx.searchHistory, pt.isByName) match
1431+
case NoType => NoType
1432+
case tp => ctx.searchHistory.linkBynameImplicit(tp.widenExpr)
14361433
end recursiveRef
14371434
end ImplicitSearch
14381435
end Implicits
@@ -1529,7 +1526,9 @@ final class SearchRoot extends SearchHistory:
15291526
* @result The corresponding TermRef, or NoType if none.
15301527
*/
15311528
override def refBynameImplicit(tpe: Type)(using Context): Type =
1532-
implicitDictionary.get(tpe).map(_._1).getOrElse(NoType)
1529+
implicitDictionary.get(tpe) match
1530+
case Some((tp, _)) => tp
1531+
case None => NoType
15331532

15341533
/**
15351534
* Define a pending dictionary entry if any.

0 commit comments

Comments
 (0)