Skip to content

Commit 818bf0b

Browse files
committed
Fix implicit scope caching bug
The issue is subtle: the `tp` in scope in `def ofTypeImplicits` is the `tp` passed to the top-level `implicitScope` method, not the `tp` passed to the recursively called `iscope`, this means that before this commit, all intermediate `OfTypeImplicit` scopes cached while computing an implicit scope had their `tp` field incorrectly set, which means that we could miss implicits in later implicit searches. Note that the `implicit_cache.scala` test worked before this commit because of the restrictions on caching that exist since b8b0f38, it is included anyway because our caching strategy might change in the future.
1 parent be418e0 commit 818bf0b

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,6 @@ trait ImplicitRunInfo { self: RunInfo =>
338338
}
339339
}
340340

341-
def ofTypeImplicits(comps: TermRefSet) = new OfTypeImplicits(tp, comps)(ctx)
342-
343341
/** The implicit scope of type `tp`
344342
* @param isLifted Type `tp` is the result of a `liftToClasses` application
345343
*/
@@ -349,9 +347,12 @@ trait ImplicitRunInfo { self: RunInfo =>
349347
ctx.typerState.ephemeral = false
350348
try {
351349
val liftedTp = if (isLifted) tp else liftToClasses(tp)
352-
val result =
353-
if (liftedTp ne tp) iscope(liftedTp, isLifted = true)
354-
else ofTypeImplicits(collectCompanions(tp))
350+
val refs =
351+
if (liftedTp ne tp)
352+
iscope(liftedTp, isLifted = true).companionRefs
353+
else
354+
collectCompanions(tp)
355+
val result = new OfTypeImplicits(tp, refs)(ctx)
355356
if (ctx.typerState.ephemeral) record("ephemeral cache miss: implicitScope")
356357
else if (cacheResult) implicitScopeCache(tp) = result
357358
result

tests/pos/implicit_cache.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class A
2+
object A {
3+
implicit def theA: A = new A
4+
}
5+
class Foo[T]
6+
object Foo {
7+
implicit def theFoo: Foo[A] = new Foo[A]
8+
}
9+
10+
object Test {
11+
def getFooA(implicit foo: Foo[A]) = foo
12+
def getA(implicit a: A) = a
13+
14+
getFooA
15+
getA
16+
}

0 commit comments

Comments
 (0)