diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 5162b3fed1b9..949e791d0496 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -636,7 +636,7 @@ trait ImplicitRunInfo: else if implicitScopeCache.contains(t) then parts += t else partSeen += t - t.dealias match + t.dealias.normalized match case t: TypeRef => if isAnchor(t.symbol) then parts += t @@ -663,7 +663,6 @@ trait ImplicitRunInfo: traverseChildren(t) case t => traverseChildren(t) - traverse(t.normalized) catch case ex: Throwable => handleRecursive("collectParts of", t.show, ex) def apply(tp: Type): collection.Set[Type] = @@ -775,6 +774,7 @@ trait ImplicitRunInfo: * if `T` is of the form `(P#x).type`, the anchors of `P`. * - If `T` is the this-type of a static object, the anchors of a term reference to that object. * - If `T` is some other this-type `P.this.type`, the anchors of `P`. + * - If `T` is match type or an applied match alias, the anchors of the normalization of `T`. * - If `T` is some other type, the union of the anchors of each constituent type of `T`. * * The _implicit scope_ of a type `tp` is the smallest set S of term references (i.e. TermRefs) @@ -787,7 +787,7 @@ trait ImplicitRunInfo: * - If `T` is a reference to an opaque type alias named `A`, S includes * a reference to an object `A` defined in the same scope as the type, if it exists, * as well as the implicit scope of `T`'s underlying type or bounds. - * - If `T` is a reference to an an abstract type or match type alias named `A`, + * - If `T` is a reference to an an abstract type or unreducible match type alias named `A`, * S includes a reference to an object `A` defined in the same scope as the type, * if it exists, as well as the implicit scopes of `T`'s lower and upper bound, * if present. diff --git a/tests/neg/i20071.scala b/tests/neg/i20071.scala new file mode 100644 index 000000000000..2d3dd5fe17d1 --- /dev/null +++ b/tests/neg/i20071.scala @@ -0,0 +1,28 @@ + +trait Scope +object Scope: + given i: Int = ??? + +type ReferencesScope[S] >: Int <: Int + +type ScopeToInt[Why] = Why match + case Scope => Int + +def foo[T](using d: ReferencesScope[T]): Any = ??? + +def bar[T](using d: ScopeToInt[T]): Any = ??? + +def test: Unit = + foo[Scope] // ok + bar[Scope] // error + + import Scope.i + bar[Scope] // ok + + /* + Before the changes: + `ScopeToInt[Scope]` may or may not be reduced before implicit search, + thereby impacting the scope considered for the search. `Scope.i` is included + iff `Scope` still appears in the type, which is the case only before reduction. + In contrast, `ReferencesScope[Scope]` is ok since it will never lose the anchor. + */ diff --git a/tests/pos/i15183/test_2.scala b/tests/pos/i15183/test_2.scala index 2069d5637734..eeb3848449be 100644 --- a/tests/pos/i15183/test_2.scala +++ b/tests/pos/i15183/test_2.scala @@ -1,4 +1,8 @@ // Fails in each cases below +import Decoder.{derived as _, given} +// NOTE Decoder.derived is already in the implicit scope +// but the others require an import as they depend on match type reduction + enum Env derives Decoder: case Local,Sit,Prod