From 3ee247381c9c6bfb3065d600c2283c68b4adb17d Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 3 Apr 2024 15:17:11 +0200 Subject: [PATCH] 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. --- .../dotty/tools/dotc/typer/Implicits.scala | 9 +- .../dotty/tools/dotc/typer/ImportInfo.scala | 2 - tests/neg/i15183.check | 96 +++++++++++++++++++ tests/{pos => neg}/i15183/decoder_1.scala | 0 tests/{pos => neg}/i15183/test_2.scala | 6 +- tests/neg/i20071.check | 5 + tests/neg/i20071/decoder_1.scala | 9 ++ tests/neg/i20071/test_2.scala | 3 + tests/pos/i20071.scala | 8 ++ 9 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 tests/neg/i15183.check rename tests/{pos => neg}/i15183/decoder_1.scala (100%) rename tests/{pos => neg}/i15183/test_2.scala (61%) create mode 100644 tests/neg/i20071.check create mode 100644 tests/neg/i20071/decoder_1.scala create mode 100644 tests/neg/i20071/test_2.scala create mode 100644 tests/pos/i20071.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 5162b3fed1b9..068098762b97 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -615,9 +615,9 @@ trait ImplicitRunInfo: if migrateTo3 then false else sym.is(Package) || sym.isPackageObject /** Is `sym` an anchor type for which givens may exist? Anchor types are classes, - * opaque type aliases, match aliases and abstract types, but not type parameters - * or package objects. - */ + * abstract types, opaque type aliases, and unreducible match aliases, but not type parameters + * or package objects. + */ private def isAnchor(sym: Symbol) = sym.isClass && !isExcluded(sym) || sym.isOpaqueAlias @@ -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] = diff --git a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala index 78cba674bfff..04e6f03565d5 100644 --- a/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala +++ b/compiler/src/dotty/tools/dotc/typer/ImportInfo.scala @@ -180,8 +180,6 @@ class ImportInfo(symf: Context ?=> Symbol, assert(myUnimported != null) myUnimported.uncheckedNN - private val isLanguageImport: Boolean = untpd.languageImport(qualifier).isDefined - private var myUnimported: Symbol | Null = uninitialized private var featureCache: SimpleIdentityMap[TermName, java.lang.Boolean] = SimpleIdentityMap.empty diff --git a/tests/neg/i15183.check b/tests/neg/i15183.check new file mode 100644 index 000000000000..6412ab96be33 --- /dev/null +++ b/tests/neg/i15183.check @@ -0,0 +1,96 @@ + +-- [E172] Type Error: tests/neg/i15183/test_2.scala:2:17 --------------------------------------------------------------- +2 |enum Env derives Decoder: // error + | ^ + |No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder. + |I found: + | + | Decoder.summonTuple[(Env.Local : Env), ((Env.Sit : Env), (Env.Prod : Env))]( + | Decoder.derived[(Env.Local : Env)]( + | Env.Local.$asInstanceOf[ + | scala.deriving.Mirror.Singleton{ + | type MirroredMonoType = (Env.Local : Env); type MirroredType = (Env.Local : Env); + | type MirroredLabel = ("Local" : String) + | } + | ], + | /* missing */summon[Tuple.Map[?1.MirroredElemTypes, Decoder]]), + | ???) + | + |But no implicit values were found that match type Tuple.Map[?1.MirroredElemTypes, Decoder] + | + |where: ?1 is an unknown value of type scala.deriving.Mirror.Singleton{ + | type MirroredMonoType = (Env.Local : Env); type MirroredType = (Env.Local : Env); + | type MirroredLabel = ("Local" : String) + |} + |. + | + |Note: a match type could not be fully reduced: + | + | trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder] + | failed since selector m.MirroredElemTypes + | does not match case EmptyTuple => EmptyTuple + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case h *: t => Decoder[h] *: Tuple.Map[t, Decoder] +-- [E172] Type Error: tests/neg/i15183/test_2.scala:5:18 --------------------------------------------------------------- +5 |enum Env2 derives Decoder: // error + | ^ + |No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder. + |I found: + | + | Decoder.summonTuple[Env2.Local, (Env2.Sit, Env2.Prod)]( + | Decoder.derived[Env2.Local]( + | Env2.Local.$asInstanceOf[ + | scala.deriving.Mirror.Product{ + | type MirroredMonoType = Env2.Local; type MirroredType = Env2.Local; type MirroredLabel = ("Local" : String); + | type MirroredElemTypes = EmptyTuple.type; type MirroredElemLabels = EmptyTuple.type + | } + | ], + | /* missing */summon[Tuple.Map[EmptyTuple.type, Decoder]]), + | ???) + | + |But no implicit values were found that match type Tuple.Map[EmptyTuple.type, Decoder]. + | + |Note: a match type could not be fully reduced: + | + | trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder] + | failed since selector m.MirroredElemTypes + | does not match case EmptyTuple => EmptyTuple + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case h *: t => Decoder[h] *: Tuple.Map[t, Decoder] +-- [E172] Type Error: tests/neg/i15183/test_2.scala:10:19 -------------------------------------------------------------- +10 |enum Shape derives Decoder: // error + | ^ + |No given instance of type Tuple.Map[m.MirroredElemTypes, Decoder] was found for parameter d of given instance derived in object Decoder. + |I found: + | + | Decoder.summonTuple[Shape.Rectangle, Shape.Circle *: EmptyTuple.type]( + | Decoder.derived[Shape.Rectangle]( + | Shape.Rectangle.$asInstanceOf[ + | scala.deriving.Mirror.Product{ + | type MirroredMonoType = Shape.Rectangle; type MirroredType = Shape.Rectangle; + | type MirroredLabel = ("Rectangle" : String); type MirroredElemTypes = (Double, Double); + | type MirroredElemLabels = (("width" : String), ("height" : String)) + | } + | ], + | Decoder.summonTuple[Double, Double *: EmptyTuple.type](Decoder.given_Decoder_Double, + | Decoder.summonTuple[Double, EmptyTuple.type](Decoder.given_Decoder_Double, + | /* missing */summon[Tuple.Map[EmptyTuple.type, Decoder]]) + | ) + | ), + | ???) + | + |But no implicit values were found that match type Tuple.Map[EmptyTuple.type, Decoder]. + | + |Note: a match type could not be fully reduced: + | + | trying to reduce Tuple.Map[m.MirroredElemTypes, Decoder] + | failed since selector m.MirroredElemTypes + | does not match case EmptyTuple => EmptyTuple + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case h *: t => Decoder[h] *: Tuple.Map[t, Decoder] diff --git a/tests/pos/i15183/decoder_1.scala b/tests/neg/i15183/decoder_1.scala similarity index 100% rename from tests/pos/i15183/decoder_1.scala rename to tests/neg/i15183/decoder_1.scala diff --git a/tests/pos/i15183/test_2.scala b/tests/neg/i15183/test_2.scala similarity index 61% rename from tests/pos/i15183/test_2.scala rename to tests/neg/i15183/test_2.scala index 2069d5637734..3554c833991a 100644 --- a/tests/pos/i15183/test_2.scala +++ b/tests/neg/i15183/test_2.scala @@ -1,12 +1,12 @@ // Fails in each cases below -enum Env derives Decoder: +enum Env derives Decoder: // error case Local,Sit,Prod -enum Env2 derives Decoder: +enum Env2 derives Decoder: // error case Local() case Sit() case Prod() -enum Shape derives Decoder: +enum Shape derives Decoder: // error case Rectangle(width: Double, height: Double) case Circle(radius: Double) diff --git a/tests/neg/i20071.check b/tests/neg/i20071.check new file mode 100644 index 000000000000..a499317e96df --- /dev/null +++ b/tests/neg/i20071.check @@ -0,0 +1,5 @@ + +-- [E172] Type Error: tests/neg/i20071/test_2.scala:3:20 --------------------------------------------------------------- +3 |def test: Unit = bar // error + | ^ + | No given instance of type M[Decoder] was found for parameter d of method bar diff --git a/tests/neg/i20071/decoder_1.scala b/tests/neg/i20071/decoder_1.scala new file mode 100644 index 000000000000..01e358818df0 --- /dev/null +++ b/tests/neg/i20071/decoder_1.scala @@ -0,0 +1,9 @@ +// decoder_1.scala +trait Decoder +object Decoder: + given foo: Int = ??? + +def bar(using d: M[Decoder]): Any = ??? + +type M[Y] = Y match + case Decoder => Int \ No newline at end of file diff --git a/tests/neg/i20071/test_2.scala b/tests/neg/i20071/test_2.scala new file mode 100644 index 000000000000..61bccde9bd70 --- /dev/null +++ b/tests/neg/i20071/test_2.scala @@ -0,0 +1,3 @@ +// test_2.scala +// should fail, does when compiling at the same time as decoder_2.scala +def test: Unit = bar // error \ No newline at end of file diff --git a/tests/pos/i20071.scala b/tests/pos/i20071.scala new file mode 100644 index 000000000000..5fead38133e3 --- /dev/null +++ b/tests/pos/i20071.scala @@ -0,0 +1,8 @@ +trait Decoder +object Decoder: + given foo: Int = ??? + +type DecoderToInt[Why] >: Int <: Int + +def bar[T](using d: DecoderToInt[T]): Any = ??? +def test: Unit = bar[Decoder] \ No newline at end of file