@@ -55,11 +55,13 @@ object Implicits:
5555 }
5656
5757 /** An eligible implicit candidate, consisting of an implicit reference and a nesting level */
58- case class Candidate (implicitRef : ImplicitRef , kind : Candidate .Kind , level : Int ) extends RefAndLevel {
58+ case class Candidate (implicitRef : ImplicitRef , kind : Candidate .Kind , level : Int ) extends RefAndLevel with Showable {
5959 def ref : TermRef = implicitRef.underlyingRef
6060
6161 def isExtension = (kind & Candidate .Extension ) != 0
6262 def isConversion = (kind & Candidate .Conversion ) != 0
63+
64+ def toText (printer : Printer ): Text = printer.toText(this )
6365 }
6466 object Candidate {
6567 type Kind = Int
@@ -331,6 +333,7 @@ object Implicits:
331333 else if outerEligible.isEmpty then ownEligible
332334 else
333335 def filter (xs : List [Candidate ], remove : List [Candidate ]) =
336+ // Drop candidates that are shadowed by candidates in "remove"
334337 val shadowed = remove.map(_.ref.implicitName).toSet
335338 xs.filterConserve(cand => ! shadowed.contains(cand.ref.implicitName))
336339
@@ -342,7 +345,22 @@ object Implicits:
342345 if ! migrateTo3(using irefCtx) && level == outer.level && (preferDefinitions || preferNamedImport) then
343346 // special cases: definitions beat imports, and named imports beat
344347 // wildcard imports, provided both are in contexts with same scope
345- filter(ownEligible, outerEligible) ::: outerEligible
348+
349+ // Using only the outer candidates at the same level as us,
350+ // remove from our own eligibles any shadowed candidate.
351+ // This removes locally imported candidates from shadowing local definitions, (foo's in i18316)
352+ // but without a remotely imported candidate removing a more locally imported candidates (mkFoo's in i18183)
353+ val ownEligible1 = filter(ownEligible, outerEligible.filter(_.level == level))
354+
355+ // Remove, from the outer eligibles, any candidate shadowed by one of our own candidates,
356+ // provided that the outer eligibles aren't at the same level (so actually shadows).
357+ // This complements the filtering of our own eligible candidates, by removing candidates in the outer candidates
358+ // that are low-level priority and shadowed by our candidates. E.g. the outer import Imp.mkFoo in i18183.
359+ val shadowed = ownEligible.map(_.ref.implicitName).toSet
360+ val outerEligible1 =
361+ outerEligible.filterConserve(cand => cand.level == level || ! shadowed.contains(cand.ref.implicitName))
362+
363+ ownEligible1 ::: outerEligible1
346364 else
347365 ownEligible ::: filter(outerEligible, ownEligible)
348366
0 commit comments