Skip to content

Commit 6a898ad

Browse files
committed
Fix #9928: Don't treat import contexts as properly nested
This avoids surprises since context stacks sometimes have an import context in more deeply nested position than the enclosing definition scope. It also corresponds to the rule for name resolution, where we treat an inner import and an outer definition of the same name as ambiguous.
1 parent f0bbd95 commit 6a898ad

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ object Contexts {
247247
else
248248
outer.implicits
249249
if (implicitRefs.isEmpty) outerImplicits
250-
else new ContextualImplicits(implicitRefs, outerImplicits)(this)
250+
else new ContextualImplicits(implicitRefs, outerImplicits, isImportContext)(this)
251251
}
252252
implicitsCache
253253
}
@@ -777,7 +777,7 @@ object Contexts {
777777

778778
@sharable object NoContext extends Context(null) {
779779
source = NoSource
780-
override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null)(this)
780+
override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null, false)(this)
781781
}
782782

783783
/** A context base defines state and associated methods that exist once per

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,10 @@ object Implicits:
295295
* name, b, whereas the name of the symbol is the original name, a.
296296
* @param outerCtx the next outer context that makes visible further implicits
297297
*/
298-
class ContextualImplicits(val refs: List[ImplicitRef], val outerImplicits: ContextualImplicits)(initctx: Context) extends ImplicitRefs(initctx) {
298+
class ContextualImplicits(
299+
val refs: List[ImplicitRef],
300+
val outerImplicits: ContextualImplicits,
301+
isImport: Boolean)(initctx: Context) extends ImplicitRefs(initctx) {
299302
private val eligibleCache = EqHashMap[Type, List[Candidate]]()
300303

301304
/** The level increases if current context has a different owner or scope than
@@ -304,7 +307,8 @@ object Implicits:
304307
*/
305308
override val level: Int =
306309
if outerImplicits == null then 1
307-
else if migrateTo3(using irefCtx)
310+
else if isImport
311+
|| migrateTo3(using irefCtx)
308312
|| (irefCtx.owner eq outerImplicits.irefCtx.owner)
309313
&& (irefCtx.scope eq outerImplicits.irefCtx.scope)
310314
&& !refs.head.implicitName.is(LazyImplicitName)
@@ -370,7 +374,7 @@ object Implicits:
370374
val outerExcluded = outerImplicits exclude root
371375
if (irefCtx.importInfo.site.termSymbol == root) outerExcluded
372376
else if (outerExcluded eq outerImplicits) this
373-
else new ContextualImplicits(refs, outerExcluded)(irefCtx)
377+
else new ContextualImplicits(refs, outerExcluded, isImport)(irefCtx)
374378
}
375379
}
376380

tests/neg/i9928.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
trait Magic[F]:
2+
extension (x: Int) def read: F
3+
4+
object Magic:
5+
given Magic[String]:
6+
extension(x: Int) def read: String =
7+
println("In string")
8+
s"$x"
9+
10+
opaque type Foo = String
11+
object Foo:
12+
import Magic.{given _}
13+
def apply(s: String): Foo = s
14+
15+
given Magic[Foo]:
16+
extension (x: Int) def read: Foo =
17+
println("In foo")
18+
Foo(s"$x")
19+
20+
def test: Unit =
21+
(3.read: Foo) // error: ambiguous
22+
23+
24+
@main def Test = {
25+
Foo.test
26+
}

0 commit comments

Comments
 (0)