Skip to content

Commit a563208

Browse files
committed
Select local implicits over name-imported over wildcard imported
1 parent ed319e8 commit a563208

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ object Implicits:
299299
class ContextualImplicits(
300300
val refs: List[ImplicitRef],
301301
val outerImplicits: ContextualImplicits | Null,
302-
isImport: Boolean)(initctx: Context) extends ImplicitRefs(initctx) {
302+
val isImport: Boolean)(initctx: Context) extends ImplicitRefs(initctx) {
303303
private val eligibleCache = EqHashMap[Type, List[Candidate]]()
304304

305305
/** The level increases if current context has a different owner or scope than
@@ -330,8 +330,19 @@ object Implicits:
330330
if ownEligible.isEmpty then outerEligible
331331
else if outerEligible.isEmpty then ownEligible
332332
else
333-
val shadowed = ownEligible.map(_.ref.implicitName).toSet
334-
ownEligible ::: outerEligible.filterConserve(cand => !shadowed.contains(cand.ref.implicitName))
333+
def filter(xs: List[Candidate], remove: List[Candidate]) =
334+
val shadowed = remove.map(_.ref.implicitName).toSet
335+
xs.filterConserve(cand => !shadowed.contains(cand.ref.implicitName))
336+
def isWildcardImport(using Context) = ctx.importInfo.nn.isWildcardImport
337+
if (irefCtx.scope eq irefCtx.outer.scope) && (
338+
isImport && !outerImplicits.nn.isImport
339+
|| isWildcardImport && !isWildcardImport(using outerImplicits.nn.irefCtx)
340+
) then
341+
// special cases: definitions beat imports, and named imports beat
342+
// wildcard imports, provided both are in contexts with same scope
343+
filter(ownEligible, outerEligible) ::: outerEligible
344+
else
345+
ownEligible ::: filter(outerEligible, ownEligible)
335346

336347
def uncachedEligible(tp: Type)(using Context): List[Candidate] =
337348
Stats.record("uncached eligible")

tests/run/i18183.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
case class Foo(n: Int)
2+
3+
class Bar(n: Int):
4+
implicit val foo: Foo = new Foo(n)
5+
6+
class InMethod:
7+
def wild(bar: Bar): Unit =
8+
import bar._
9+
implicit val foo: Foo = new Foo(2)
10+
assert(foo eq implicitly[Foo])
11+
12+
def named(bar: Bar): Unit =
13+
import bar.foo
14+
implicit val foo: Foo = new Foo(2)
15+
assert(foo eq implicitly[Foo])
16+
17+
def namedWild(bar: Bar): Unit =
18+
val bar2 = new Bar(2)
19+
import bar.foo
20+
import bar2._
21+
assert(bar.foo eq implicitly[Foo])
22+
23+
def wildNamed(bar: Bar): Unit =
24+
val bar2 = new Bar(2)
25+
import bar.foo
26+
import bar2._
27+
assert(bar.foo eq implicitly[Foo])
28+
29+
class InClass(bar: Bar):
30+
import bar._
31+
implicit val foo: Foo = new Foo(2)
32+
assert(foo eq implicitly[Foo])
33+
34+
object Test:
35+
def main(args: Array[String]): Unit =
36+
val bar = new Bar(1)
37+
new InMethod().wild(bar)
38+
new InMethod().named(bar)
39+
new InMethod().namedWild(bar)
40+
new InMethod().wildNamed(bar)
41+
new InClass(bar)

0 commit comments

Comments
 (0)