Skip to content

Commit b28dfa2

Browse files
Normalize type before collecting parts determining implicit scope
This is necessary to ensure the implicit scope is consistent when involving match types, since they may or may not have been reduced before implicit search. We can for example get different results when loading from tasty than when in the same run. Fixes #20071
1 parent 9a5b9b4 commit b28dfa2

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ trait ImplicitRunInfo:
636636
else if implicitScopeCache.contains(t) then parts += t
637637
else
638638
partSeen += t
639-
t.dealias match
639+
t.dealias.normalized match
640640
case t: TypeRef =>
641641
if isAnchor(t.symbol) then
642642
parts += t
@@ -663,7 +663,6 @@ trait ImplicitRunInfo:
663663
traverseChildren(t)
664664
case t =>
665665
traverseChildren(t)
666-
traverse(t.normalized)
667666
catch case ex: Throwable => handleRecursive("collectParts of", t.show, ex)
668667

669668
def apply(tp: Type): collection.Set[Type] =
@@ -775,6 +774,7 @@ trait ImplicitRunInfo:
775774
* if `T` is of the form `(P#x).type`, the anchors of `P`.
776775
* - If `T` is the this-type of a static object, the anchors of a term reference to that object.
777776
* - If `T` is some other this-type `P.this.type`, the anchors of `P`.
777+
* - If `T` is match type or an applied match alias, the anchors of the normalization of `T`.
778778
* - If `T` is some other type, the union of the anchors of each constituent type of `T`.
779779
*
780780
* The _implicit scope_ of a type `tp` is the smallest set S of term references (i.e. TermRefs)

tests/neg/i20071.scala

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
trait Scope
3+
object Scope:
4+
given i: Int = ???
5+
6+
type ReferencesScope[S] >: Int <: Int
7+
8+
type ScopeToInt[Why] = Why match
9+
case Scope => Int
10+
11+
def foo[T](using d: ReferencesScope[T]): Any = ???
12+
13+
def bar[T](using d: ScopeToInt[T]): Any = ???
14+
15+
def test: Unit =
16+
foo[Scope] // ok
17+
bar[Scope] // error
18+
19+
/*
20+
Before the changes:
21+
`ScopeToInt[Scope]` may or may not be reduced before implicits, thereby impacting the scope search.
22+
`Scope.i` is considered iff `Scope` still appears in the type, which is only the case before reduction.
23+
In contrast, `ReferencesScope[Scope]` is ok since it will never lose the anchor.
24+
*/
25+

tests/pos/i15183/test_2.scala

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
// Fails in each cases below
2+
import Decoder.{derived as _, given}
3+
// NOTE Decoder.derived is already in the implicit scope
4+
// but the others require an import as they depend on match type reduction
5+
26
enum Env derives Decoder:
37
case Local,Sit,Prod
48

0 commit comments

Comments
 (0)