Skip to content

Commit dea58c1

Browse files
committed
Implement MatchType reduction avoidance on typeSize
1 parent 6490a4c commit dea58c1

File tree

4 files changed

+23
-16
lines changed

4 files changed

+23
-16
lines changed

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3944,21 +3944,22 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
39443944
MatchTypeTrace.noInstance(scrut, cas, fails)
39453945
NoType
39463946
case MatchResult.Reduced(tp) =>
3947-
val reductionStatus = ctx.property(Reduction) match
3947+
val reductionStack = ctx.property(Reduction) match
39483948
case Some(stack) => stack
39493949
case None => Stack[Type]()
39503950

39513951
println(s"Scrutinee ${scrut.show}")
3952-
println(s"Reduction stack: ${reductionStatus.map(_.show)}")
3952+
println(s"Reduction stack: ${reductionStack.map(_.show)}")
39533953

3954-
if reductionStatus.contains(tp) then
3954+
if reductionStack.contains(tp) then
39553955
ErrorType(em"Cyclic match type reduction detected")
3956+
else if !reductionStack.isEmpty && tp.typeSize(false) > reductionStack.top.typeSize(false) then
3957+
ErrorType(em"Non-decresing match type reduction detected: ${tp.show}")
39563958
else
3957-
val bodyType = {
3958-
reductionStatus.push(tp)
3959-
given Context = ctx.fresh.setProperty(Reduction, reductionStatus)
3959+
val bodyType =
3960+
reductionStack.push(tp)
3961+
given Context = ctx.fresh.setProperty(Reduction, reductionStack)
39603962
tp.simplified
3961-
}
39623963
bodyType
39633964

39643965
case MatchResult.ReducedAndDisjoint =>

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,8 +2095,8 @@ object Types extends TypeUtils {
20952095
(new CoveringSetAccumulator).apply(Set.empty[Symbol], this)
20962096

20972097
/** The number of applications and refinements in this type, after all aliases are expanded */
2098-
def typeSize(using Context): Int =
2099-
(new TypeSizeAccumulator).apply(0, this)
2098+
def typeSize(normalizeMatchTypes: Boolean = true)(using Context): Int =
2099+
(new TypeSizeAccumulator).apply(0, this, normalizeMatchTypes)
21002100

21012101
/** Convert to text */
21022102
def toText(printer: Printer): Text = printer.toText(this)
@@ -7123,12 +7123,16 @@ object Types extends TypeUtils {
71237123

71247124
class TypeSizeAccumulator(using Context) extends TypeAccumulator[Int] {
71257125
var seen = util.HashSet[Type](initialCapacity = 8)
7126-
def apply(n: Int, tp: Type): Int =
7126+
def apply(n: Int, tp: Type, normalizeMatchTypes: Boolean): Int =
71277127
tp match {
71287128
case tp: AppliedType =>
7129-
val tpNorm = tp.tryNormalize
7130-
if tpNorm.exists then apply(n, tpNorm)
7131-
else foldOver(n + 1, tp)
7129+
if !normalizeMatchTypes && tp.isMatchAlias then
7130+
println(s"TypeSizeAccumulator: skipping match alias ${tp.show}")
7131+
foldOver(n + 1, tp)
7132+
else
7133+
val tpNorm = tp.tryNormalize
7134+
if tpNorm.exists then apply(n, tpNorm)
7135+
else foldOver(n + 1, tp)
71327136
case tp: RefinedType =>
71337137
foldOver(n + 1, tp)
71347138
case tp: TypeRef if tp.info.isTypeAlias =>
@@ -7146,6 +7150,8 @@ object Types extends TypeUtils {
71467150
case _ =>
71477151
foldOver(n, tp)
71487152
}
7153+
7154+
def apply(n: Int, tp: Type): Int = apply(n, tp, normalizeMatchTypes = false)
71497155
}
71507156

71517157
class CoveringSetAccumulator(using Context) extends TypeAccumulator[Set[Symbol]] {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,7 @@ trait Implicits:
18271827

18281828
/** Fields needed for divergence checking */
18291829
@threadUnsafe lazy val ptCoveringSet = wideProto.coveringSet
1830-
@threadUnsafe lazy val ptSize = wideProto.typeSize
1830+
@threadUnsafe lazy val ptSize = wideProto.typeSize()
18311831
@threadUnsafe lazy val wildPt = wildApprox(wideProto)
18321832

18331833
/**
@@ -1967,7 +1967,7 @@ case class OpenSearch(cand: Candidate, pt: Type, outer: SearchHistory)(using Con
19671967
// by nested implicit searches, thus leading to types in search histories
19681968
// that grow larger the deeper the search gets. This can mask divergence.
19691969
// An example is in neg/9504.scala
1970-
lazy val typeSize = pt.typeSize
1970+
lazy val typeSize = pt.typeSize()
19711971
lazy val coveringSet = pt.coveringSet
19721972
end OpenSearch
19731973

compiler/test/dotty/tools/dotc/typer/DivergenceChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class DivergenceCheckerTests extends DottyTest {
5656

5757
tpes.lazyZip(expectedSizes).lazyZip(expectedCoveringSets).foreach {
5858
case (tpe, expectedSize, expectedCoveringSet) =>
59-
val size = tpe.typeSize
59+
val size = tpe.typeSize()
6060
val cs = tpe.coveringSet
6161

6262
assertTrue(size == expectedSize)

0 commit comments

Comments
 (0)