Skip to content

Commit 212ff60

Browse files
committed
More robust comparison of type constructors in provablyDisjoint
A type comparison with `==` should be used only for exploring opportunities to optimize, never where it affects the logic. I.e. we need to always have a fallback that checks via `=:=`. Fixes #11393
1 parent 0273336 commit 212ff60

File tree

5 files changed

+20
-6
lines changed

5 files changed

+20
-6
lines changed

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ object Printers {
3131
val init = noPrinter
3232
val inlining = noPrinter
3333
val interactiv = noPrinter
34+
val matchTypes = noPrinter
3435
val nullables = noPrinter
3536
val overload = noPrinter
3637
val patmatch = noPrinter

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import collection.mutable
1111
import util.Stats
1212
import config.Config
1313
import config.Feature.migrateTo3
14-
import config.Printers.{constr, subtyping, gadts, noPrinter}
14+
import config.Printers.{constr, subtyping, gadts, matchTypes, noPrinter}
1515
import TypeErasure.{erasedLub, erasedGlb}
1616
import TypeApplications._
1717
import Variances.{Variance, variancesConform}
@@ -2408,7 +2408,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24082408
* property that in all possible contexts, the same match type expression
24092409
* is either stuck or reduces to the same case.
24102410
*/
2411-
def provablyDisjoint(tp1: Type, tp2: Type)(using Context): Boolean = {
2411+
def provablyDisjoint(tp1: Type, tp2: Type)(using Context): Boolean = trace(i"provable disjoint $tp1, $tp2", matchTypes) {
24122412
// println(s"provablyDisjoint(${tp1.show}, ${tp2.show})")
24132413

24142414
def isEnumValueOrModule(ref: TermRef): Boolean =
@@ -2452,7 +2452,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
24522452
decompose(cls2, tp2).forall(x => provablyDisjoint(x, tp1))
24532453
else
24542454
false
2455-
case (AppliedType(tycon1, args1), AppliedType(tycon2, args2)) if tycon1 == tycon2 =>
2455+
case (AppliedType(tycon1, args1), AppliedType(tycon2, args2))
2456+
if tycon1.typeSymbol == tycon2.typeSymbol && tycon1 =:= tycon2 =>
24562457
// It is possible to conclude that two types applies are disjoint by
24572458
// looking at covariant type parameters if the said type parameters
24582459
// are disjoin and correspond to fields.
@@ -2768,7 +2769,7 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
27682769
* None if the match fails and we should consider the following cases
27692770
* because scrutinee and pattern do not overlap
27702771
*/
2771-
def matchCase(cas: Type): Option[Type] = {
2772+
def matchCase(cas: Type): Option[Type] = trace(i"match case $cas vs $scrut", matchTypes) {
27722773
val cas1 = cas match {
27732774
case cas: HKTypeLambda =>
27742775
caseLambda = constrained(cas)

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import config.Config
3333
import annotation.{tailrec, constructorOnly}
3434
import language.implicitConversions
3535
import scala.util.hashing.{ MurmurHash3 => hashing }
36-
import config.Printers.{core, typr}
36+
import config.Printers.{core, typr, matchTypes}
3737
import reporting.{trace, Message}
3838
import java.lang.ref.WeakReference
3939

@@ -4489,7 +4489,7 @@ object Types {
44894489
record("MatchType.reduce computed")
44904490
if (myReduced != null) record("MatchType.reduce cache miss")
44914491
myReduced =
4492-
trace(i"reduce match type $this $hashCode", typr, show = true) {
4492+
trace(i"reduce match type $this $hashCode", matchTypes, show = true) {
44934493
def matchCases(cmp: TrackingTypeComparer): Type =
44944494
try cmp.matchCases(scrutinee.normalized, cases)
44954495
catch case ex: Throwable =>

tests/pos/i11393/Format_1.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Formatt:
2+
type ToFormat[X <: Tuple] = X match
3+
case EmptyTuple => String
4+
case '%' *: 's' *: ts => (String => ToFormat[ts])
5+
case Char *: ts => ToFormat[ts]
6+
7+

tests/pos/i11393/Test_2.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@main def hello: Unit = {
2+
val x: Formatt.ToFormat['a' *: EmptyTuple] = ""
3+
4+
5+
}

0 commit comments

Comments
 (0)