Skip to content

Commit 3ee2473

Browse files
committed
Normalize match types before computing implicit scopes
We now try to reduce match types before computing their contributions to an implicit scope. This avoids problems where joint and separate compilations gave different results, as in #20071 and #15183. Background: If a match type is reducible to a type R the compiler is free to replace the match type with R. That should not affect the implicit scope computation. Consequently, we have to try to reduce match types before computing their contributions to an implicit scope. #20071 and #15183 are really the same problem. Both used to compile in sequence and both gave an implicit not found error when two files were compiled together. In #15183 a weird match type was constructed intentionally, in order to avoid an otherwise necessary given import. That exploited a bug in the compiler which this PR fixes.
1 parent c8c3bde commit 3ee2473

File tree

9 files changed

+128
-10
lines changed

9 files changed

+128
-10
lines changed

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

+4-5
Original file line numberDiff line numberDiff line change
@@ -615,9 +615,9 @@ trait ImplicitRunInfo:
615615
if migrateTo3 then false else sym.is(Package) || sym.isPackageObject
616616

617617
/** Is `sym` an anchor type for which givens may exist? Anchor types are classes,
618-
* opaque type aliases, match aliases and abstract types, but not type parameters
619-
* or package objects.
620-
*/
618+
* abstract types, opaque type aliases, and unreducible match aliases, but not type parameters
619+
* or package objects.
620+
*/
621621
private def isAnchor(sym: Symbol) =
622622
sym.isClass && !isExcluded(sym)
623623
|| sym.isOpaqueAlias
@@ -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] =

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

-2
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,6 @@ class ImportInfo(symf: Context ?=> Symbol,
180180
assert(myUnimported != null)
181181
myUnimported.uncheckedNN
182182

183-
private val isLanguageImport: Boolean = untpd.languageImport(qualifier).isDefined
184-
185183
private var myUnimported: Symbol | Null = uninitialized
186184

187185
private var featureCache: SimpleIdentityMap[TermName, java.lang.Boolean] = SimpleIdentityMap.empty

tests/neg/i15183.check

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
-- [E172] Type Error: tests/neg/i15183/test_2.scala:2:17 ---------------------------------------------------------------
3+
2 |enum Env derives Decoder: // error
4+
| ^
5+
|No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder.
6+
|I found:
7+
|
8+
| Decoder.summonTuple[(Env.Local : Env), ((Env.Sit : Env), (Env.Prod : Env))](
9+
| Decoder.derived[(Env.Local : Env)](
10+
| Env.Local.$asInstanceOf[
11+
| scala.deriving.Mirror.Singleton{
12+
| type MirroredMonoType = (Env.Local : Env); type MirroredType = (Env.Local : Env);
13+
| type MirroredLabel = ("Local" : String)
14+
| }
15+
| ],
16+
| /* missing */summon[Tuple.Map[?1.MirroredElemTypes, Decoder]]),
17+
| ???)
18+
|
19+
|But no implicit values were found that match type Tuple.Map[?1.MirroredElemTypes, Decoder]
20+
|
21+
|where: ?1 is an unknown value of type scala.deriving.Mirror.Singleton{
22+
| type MirroredMonoType = (Env.Local : Env); type MirroredType = (Env.Local : Env);
23+
| type MirroredLabel = ("Local" : String)
24+
|}
25+
|.
26+
|
27+
|Note: a match type could not be fully reduced:
28+
|
29+
| trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder]
30+
| failed since selector m.MirroredElemTypes
31+
| does not match case EmptyTuple => EmptyTuple
32+
| and cannot be shown to be disjoint from it either.
33+
| Therefore, reduction cannot advance to the remaining case
34+
|
35+
| case h *: t => Decoder[h] *: Tuple.Map[t, Decoder]
36+
-- [E172] Type Error: tests/neg/i15183/test_2.scala:5:18 ---------------------------------------------------------------
37+
5 |enum Env2 derives Decoder: // error
38+
| ^
39+
|No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder.
40+
|I found:
41+
|
42+
| Decoder.summonTuple[Env2.Local, (Env2.Sit, Env2.Prod)](
43+
| Decoder.derived[Env2.Local](
44+
| Env2.Local.$asInstanceOf[
45+
| scala.deriving.Mirror.Product{
46+
| type MirroredMonoType = Env2.Local; type MirroredType = Env2.Local; type MirroredLabel = ("Local" : String);
47+
| type MirroredElemTypes = EmptyTuple.type; type MirroredElemLabels = EmptyTuple.type
48+
| }
49+
| ],
50+
| /* missing */summon[Tuple.Map[EmptyTuple.type, Decoder]]),
51+
| ???)
52+
|
53+
|But no implicit values were found that match type Tuple.Map[EmptyTuple.type, Decoder].
54+
|
55+
|Note: a match type could not be fully reduced:
56+
|
57+
| trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder]
58+
| failed since selector m.MirroredElemTypes
59+
| does not match case EmptyTuple => EmptyTuple
60+
| and cannot be shown to be disjoint from it either.
61+
| Therefore, reduction cannot advance to the remaining case
62+
|
63+
| case h *: t => Decoder[h] *: Tuple.Map[t, Decoder]
64+
-- [E172] Type Error: tests/neg/i15183/test_2.scala:10:19 --------------------------------------------------------------
65+
10 |enum Shape derives Decoder: // error
66+
| ^
67+
|No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder.
68+
|I found:
69+
|
70+
| Decoder.summonTuple[Shape.Rectangle, Shape.Circle *: EmptyTuple.type](
71+
| Decoder.derived[Shape.Rectangle](
72+
| Shape.Rectangle.$asInstanceOf[
73+
| scala.deriving.Mirror.Product{
74+
| type MirroredMonoType = Shape.Rectangle; type MirroredType = Shape.Rectangle;
75+
| type MirroredLabel = ("Rectangle" : String); type MirroredElemTypes = (Double, Double);
76+
| type MirroredElemLabels = (("width" : String), ("height" : String))
77+
| }
78+
| ],
79+
| Decoder.summonTuple[Double, Double *: EmptyTuple.type](Decoder.given_Decoder_Double,
80+
| Decoder.summonTuple[Double, EmptyTuple.type](Decoder.given_Decoder_Double,
81+
| /* missing */summon[Tuple.Map[EmptyTuple.type, Decoder]])
82+
| )
83+
| ),
84+
| ???)
85+
|
86+
|But no implicit values were found that match type Tuple.Map[EmptyTuple.type, Decoder].
87+
|
88+
|Note: a match type could not be fully reduced:
89+
|
90+
| trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder]
91+
| failed since selector m.MirroredElemTypes
92+
| does not match case EmptyTuple => EmptyTuple
93+
| and cannot be shown to be disjoint from it either.
94+
| Therefore, reduction cannot advance to the remaining case
95+
|
96+
| case h *: t => Decoder[h] *: Tuple.Map[t, Decoder]
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Fails in each cases below
2-
enum Env derives Decoder:
2+
enum Env derives Decoder: // error
33
case Local,Sit,Prod
44

5-
enum Env2 derives Decoder:
5+
enum Env2 derives Decoder: // error
66
case Local()
77
case Sit()
88
case Prod()
99

10-
enum Shape derives Decoder:
10+
enum Shape derives Decoder: // error
1111
case Rectangle(width: Double, height: Double)
1212
case Circle(radius: Double)

tests/neg/i20071.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
-- [E172] Type Error: tests/neg/i20071/test_2.scala:3:20 ---------------------------------------------------------------
3+
3 |def test: Unit = bar // error
4+
| ^
5+
| No given instance of type M[Decoder] was found for parameter d of method bar

tests/neg/i20071/decoder_1.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// decoder_1.scala
2+
trait Decoder
3+
object Decoder:
4+
given foo: Int = ???
5+
6+
def bar(using d: M[Decoder]): Any = ???
7+
8+
type M[Y] = Y match
9+
case Decoder => Int

tests/neg/i20071/test_2.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// test_2.scala
2+
// should fail, does when compiling at the same time as decoder_2.scala
3+
def test: Unit = bar // error

tests/pos/i20071.scala

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Decoder
2+
object Decoder:
3+
given foo: Int = ???
4+
5+
type DecoderToInt[Why] >: Int <: Int
6+
7+
def bar[T](using d: DecoderToInt[T]): Any = ???
8+
def test: Unit = bar[Decoder]

0 commit comments

Comments
 (0)