Skip to content

Commit cfe45b3

Browse files
committed
More optimzations of implicit search
1 parent 7d3adb8 commit cfe45b3

File tree

1 file changed

+51
-54
lines changed

1 file changed

+51
-54
lines changed

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

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -239,23 +239,20 @@ object Implicits:
239239
Nil
240240
else
241241
val nestedCtx = ctx.fresh.addMode(Mode.TypevarsMissContext)
242+
val candidates = new mutable.ListBuffer[Candidate]
243+
var extensionOnly = true
242244

243-
def matchingCandidate(ref: ImplicitRef, extensionOnly: Boolean): Option[Candidate] =
245+
val tryCandidate = (ref: ImplicitRef) =>
244246
var ckind = explore(candidateKind(ref.underlyingRef))(using nestedCtx)
245247
if extensionOnly then ckind &= Candidate.Extension
246-
if ckind == Candidate.None then None
247-
else Some(new Candidate(ref, ckind, level))
248-
249-
val extensionCandidates =
250-
if considerExtension then
251-
companionRefs.toList
252-
.filterConserve(!_.symbol.isOneOf(GivenOrImplicit)) // implicit objects are already in `refs`
253-
.flatMap(matchingCandidate(_, extensionOnly = true))
254-
else
255-
Nil
256-
val implicitCandidates =
257-
refs.flatMap(matchingCandidate(_, extensionOnly = false))
258-
extensionCandidates ::: implicitCandidates
248+
if ckind != Candidate.None then
249+
candidates += Candidate(ref, ckind, level)
250+
251+
if considerExtension then
252+
companionRefs.foreach(tryCandidate)
253+
extensionOnly = false
254+
refs.foreach(tryCandidate)
255+
candidates.toList
259256
}
260257
}
261258

@@ -265,7 +262,7 @@ object Implicits:
265262
*/
266263
class OfTypeImplicits(tp: Type, override val companionRefs: TermRefSet)(initctx: Context) extends ImplicitRefs(initctx) {
267264
assert(initctx.typer != null)
268-
implicits.println(i"implicit scope of type $tp = ${companionRefs.toList}%, %")
265+
implicits.println(i"implicit scope of type $tp = ${companionRefs.showAsList}%, %")
269266
@threadUnsafe lazy val refs: List[ImplicitRef] = {
270267
val buf = new mutable.ListBuffer[TermRef]
271268
for (companion <- companionRefs) buf ++= companion.implicitMembers
@@ -274,7 +271,7 @@ object Implicits:
274271

275272
/** The candidates that are eligible for expected type `tp` */
276273
@threadUnsafe lazy val eligible: List[Candidate] =
277-
trace(i"eligible($tp), companions = ${companionRefs.toList}%, %", implicitsDetailed, show = true) {
274+
trace(i"eligible($tp), companions = ${companionRefs.showAsList}%, %", implicitsDetailed, show = true) {
278275
if (refs.nonEmpty && monitored) record(s"check eligible refs in tpe", refs.length)
279276
filterMatching(tp)
280277
}
@@ -283,7 +280,7 @@ object Implicits:
283280
ref.symbol.exists && !ref.symbol.is(Private)
284281

285282
override def toString: String =
286-
i"OfTypeImplicits($tp), companions = ${companionRefs.toList}%, %; refs = $refs%, %."
283+
i"OfTypeImplicits($tp), companions = ${companionRefs.showAsList}%, %; refs = $refs%, %."
287284
}
288285

289286
/** The implicit references coming from the context.
@@ -681,41 +678,41 @@ trait ImplicitRunInfo:
681678
* - If `T` is some other type, S includes the implicit scopes of all anchors of `T`.
682679
*/
683680
def implicitScope(tp: Type)(using Context): OfTypeImplicits =
684-
object liftToAnchors extends TypeMap:
685-
override def stopAtStatic = true
686-
private val seen = TypeHashSet()
681+
implicitScopeCache.get(tp) match
682+
case Some(is) => is
683+
case None =>
684+
record(i"implicitScope")
685+
val liftToAnchors = new TypeMap:
686+
override def stopAtStatic = true
687+
private val seen = TypeHashSet()
688+
689+
def applyToUnderlying(t: TypeProxy) =
690+
if seen.contains(t) then
691+
WildcardType
692+
else
693+
seen.addEntry(t)
694+
t.underlying match
695+
case TypeBounds(lo, hi) =>
696+
if defn.isBottomTypeAfterErasure(lo) then apply(hi)
697+
else AndType.make(apply(lo), apply(hi))
698+
case u => apply(u)
687699

688-
def applyToUnderlying(t: TypeProxy) =
689-
if seen.contains(t) then
690-
WildcardType
700+
def apply(t: Type) = t.dealias match
701+
case t: TypeRef =>
702+
if t.symbol.isClass || isAnchor(t.symbol) then t else applyToUnderlying(t)
703+
case t: TypeVar => apply(t.underlying)
704+
case t: ParamRef => applyToUnderlying(t)
705+
case t: ConstantType => apply(t.underlying)
706+
case t => mapOver(t)
707+
end liftToAnchors
708+
val liftedTp = liftToAnchors(tp)
709+
if liftedTp eq tp then
710+
record(i"implicitScope unlifted")
711+
computeIScope(tp)
691712
else
692-
seen.addEntry(t)
693-
t.underlying match
694-
case TypeBounds(lo, hi) =>
695-
if defn.isBottomTypeAfterErasure(lo) then apply(hi)
696-
else AndType.make(apply(lo), apply(hi))
697-
case u => apply(u)
698-
699-
def apply(t: Type) = t.dealias match
700-
case t: TypeRef =>
701-
if t.symbol.isClass || isAnchor(t.symbol) then t else applyToUnderlying(t)
702-
case t: TypeVar => apply(t.underlying)
703-
case t: ParamRef => applyToUnderlying(t)
704-
case t: ConstantType => apply(t.underlying)
705-
case t => mapOver(t)
706-
end liftToAnchors
707-
708-
record(i"implicitScope")
709-
implicitScopeCache.getOrElse(tp, {
710-
val liftedTp = liftToAnchors(tp)
711-
if liftedTp eq tp then
712-
record(i"implicitScope unlifted")
713-
computeIScope(tp)
714-
else
715-
record(i"implicitScope lifted")
716-
val liftedIScope = implicitScopeCache.getOrElse(liftedTp, computeIScope(liftedTp))
717-
OfTypeImplicits(tp, liftedIScope.companionRefs)(runContext)
718-
})
713+
record(i"implicitScope lifted")
714+
val liftedIScope = implicitScopeCache.getOrElse(liftedTp, computeIScope(liftedTp))
715+
OfTypeImplicits(tp, liftedIScope.companionRefs)(runContext)
719716
end implicitScope
720717

721718
protected def reset(): Unit =
@@ -1204,7 +1201,7 @@ trait Implicits:
12041201
else disambiguate(found, best) match {
12051202
case retained: SearchSuccess =>
12061203
val newPending =
1207-
if (retained eq found) remaining
1204+
if (retained eq found) || remaining.isEmpty then remaining
12081205
else remaining.filter(cand =>
12091206
compareCandidate(retained, cand.ref, cand.level) <= 0)
12101207
rank(newPending, retained, rfailures)
@@ -1669,7 +1666,7 @@ sealed class TermRefSet(using Context):
16691666
if !prefixes.exists(_ =:= pre) then elems.put(sym, pre :: prefixes)
16701667

16711668
def ++= (that: TermRefSet): Unit =
1672-
that.foreach(+=)
1669+
if !that.isEmpty then that.foreach(+=)
16731670

16741671
def foreach[U](f: TermRef => U): Unit =
16751672
elems.forEach((sym: TermSymbol, prefixes: Type | List[Type]) =>
@@ -1678,13 +1675,13 @@ sealed class TermRefSet(using Context):
16781675
case prefixes: List[Type] => prefixes.foreach(pre => f(TermRef(pre, sym))))
16791676

16801677
// used only for debugging
1681-
def toList: List[TermRef] = {
1678+
def showAsList: List[TermRef] = {
16821679
val buffer = new mutable.ListBuffer[TermRef]
16831680
foreach(tr => buffer += tr)
16841681
buffer.toList
16851682
}
16861683

1687-
override def toString = toList.toString
1684+
override def toString = showAsList.toString
16881685

16891686
object TermRefSet:
16901687

0 commit comments

Comments
 (0)