Skip to content

Commit 48415d2

Browse files
committed
Optimize SearchHistory
Avoid a separate list of candidate/type pairs. Instead integrate them as fields of the search history itself.
1 parent 632922e commit 48415d2

File tree

1 file changed

+34
-31
lines changed

1 file changed

+34
-31
lines changed

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

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,24 +1362,19 @@ trait Implicits { self: Typer =>
13621362
* recursive references and emit a complete implicit dictionary when the outermost search
13631363
* is complete.
13641364
*/
1365-
abstract class SearchHistory { outer =>
1365+
abstract class SearchHistory:
13661366
val root: SearchRoot
1367-
val open: List[(Candidate, Type)]
13681367
/** Does this search history contain any by name implicit arguments. */
13691368
val byname: Boolean
1369+
def open: List[(Candidate, Type)]
13701370

13711371
/**
13721372
* Create the state for a nested implicit search.
13731373
* @param cand The candidate implicit to be explored.
13741374
* @param pt The target type for the above candidate.
13751375
* @result The nested history.
13761376
*/
1377-
def nest(cand: Candidate, pt: Type)(using Context): SearchHistory =
1378-
new SearchHistory {
1379-
val root = outer.root
1380-
val open = (cand, pt) :: outer.open
1381-
val byname = outer.byname || isByname(pt)
1382-
}
1377+
def nest(cand: Candidate, pt: Type)(using Context): OpenSearch = OpenSearch(cand, pt, this)
13831378

13841379
def isByname(tp: Type): Boolean = tp.isInstanceOf[ExprType]
13851380

@@ -1410,22 +1405,25 @@ abstract class SearchHistory { outer =>
14101405
// as we ascend the chain of open implicits to the outermost search context.
14111406

14121407
@tailrec
1413-
def loop(ois: List[(Candidate, Type)], belowByname: Boolean): Boolean =
1414-
ois match {
1415-
case Nil => false
1416-
case (hd@(cand1, tp)) :: tl =>
1417-
if (cand1.ref == cand.ref) {
1408+
def loop(history: SearchHistory, belowByname: Boolean): Boolean =
1409+
history match
1410+
case _: SearchRoot => false
1411+
case OpenSearch(cand1, tp, outer) =>
1412+
if cand1.ref == cand.ref then
14181413
val wideTp = tp.widenExpr
14191414
lazy val wildTp = wildApprox(wideTp)
14201415
lazy val tpSize = wideTp.typeSize
1421-
if (belowByname && (wildTp <:< wildPt)) false
1422-
else if (tpSize > ptSize || wideTp.coveringSet != ptCoveringSet) loop(tl, isByname(tp) || belowByname)
1423-
else tpSize < ptSize || wildTp =:= wildPt || loop(tl, isByname(tp) || belowByname)
1424-
}
1425-
else loop(tl, isByname(tp) || belowByname)
1426-
}
1416+
if belowByname && (wildTp <:< wildPt) then
1417+
false
1418+
else if tpSize > ptSize || wideTp.coveringSet != ptCoveringSet then
1419+
loop(outer, isByname(tp) || belowByname)
1420+
else
1421+
tpSize < ptSize
1422+
|| wildTp =:= wildPt
1423+
|| loop(outer, isByname(tp) || belowByname)
1424+
else loop(outer, isByname(tp) || belowByname)
14271425

1428-
loop(open, isByname(pt))
1426+
loop(this, isByname(pt))
14291427
}
14301428

14311429
/**
@@ -1457,17 +1455,16 @@ abstract class SearchHistory { outer =>
14571455
// argument as we ascend the chain of open implicits to the outermost search
14581456
// context.
14591457
@tailrec
1460-
def loop(ois: List[(Candidate, Type)], belowByname: Boolean): Type =
1461-
ois match {
1462-
case (hd@(cand, tp)) :: tl if (belowByname || isByname(tp)) && tp.widenExpr <:< widePt => tp
1463-
case (_, tp) :: tl => loop(tl, belowByname || isByname(tp))
1458+
def loop(history: SearchHistory, belowByname: Boolean): Type =
1459+
history match
1460+
case OpenSearch(cand, tp, outer) =>
1461+
if (belowByname || isByname(tp)) && tp.widenExpr <:< widePt then tp
1462+
else loop(outer, belowByname || isByname(tp))
14641463
case _ => NoType
1465-
}
14661464

1467-
loop(open, bynamePt) match {
1465+
loop(this, bynamePt) match
14681466
case NoType => NoType
14691467
case tp => ctx.searchHistory.linkBynameImplicit(tp.widenExpr)
1470-
}
14711468
}
14721469
}
14731470
}
@@ -1484,15 +1481,21 @@ abstract class SearchHistory { outer =>
14841481
def emitDictionary(span: Span, result: SearchResult)(using Context): SearchResult = result
14851482

14861483
override def toString: String = s"SearchHistory(open = $open, byname = $byname)"
1487-
}
1484+
end SearchHistory
1485+
1486+
case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory) extends SearchHistory:
1487+
val root = outer.root
1488+
val byname = outer.byname || isByname(pt)
1489+
def open = (cand, pt) :: outer.open
1490+
end OpenSearch
14881491

14891492
/**
14901493
* The the state corresponding to the outermost context of an implicit searcch.
14911494
*/
1492-
final class SearchRoot extends SearchHistory {
1495+
final class SearchRoot extends SearchHistory:
14931496
val root = this
1494-
val open = Nil
14951497
val byname = false
1498+
def open = Nil
14961499

14971500
/** The dictionary of recursive implicit types and corresponding terms for this search. */
14981501
var implicitDictionary0: mutable.Map[Type, (TermRef, tpd.Tree)] = null
@@ -1653,7 +1656,7 @@ final class SearchRoot extends SearchHistory {
16531656
success.copy(tree = blk)(success.tstate, success.gstate)
16541657
}
16551658
}
1656-
}
1659+
end SearchRoot
16571660

16581661
/** A set of term references where equality is =:= */
16591662
sealed class TermRefSet(using Context):

0 commit comments

Comments
 (0)