@@ -28,6 +28,8 @@ import NameKinds.WildcardParamName
2828import MatchTypes .isConcrete
2929import reporting .Message .Note
3030import scala .util .boundary , boundary .break
31+ import dotty .tools .dotc .util .Property
32+ import scala .collection .mutable .Stack
3133
3234/** Provides methods to compare types.
3335 */
@@ -3594,6 +3596,8 @@ object MatchReducer:
35943596 case Stuck => " Stuck"
35953597 case NoInstance (fails) => " NoInstance(" ~ Text (fails.map(p.toText(_) ~ p.toText(_)), " , " ) ~ " )"
35963598
3599+ val Reduction = new Property .Key [Stack [Type ]]
3600+
35973601/** A type comparer for reducing match types.
35983602 * TODO: Not sure this needs to be a type comparer. Can we make it a
35993603 * separate class?
@@ -3940,7 +3944,23 @@ class MatchReducer(initctx: Context) extends TypeComparer(initctx) {
39403944 MatchTypeTrace .noInstance(scrut, cas, fails)
39413945 NoType
39423946 case MatchResult .Reduced (tp) =>
3943- tp.simplified
3947+ val reductionStatus = ctx.property(Reduction ) match
3948+ case Some (stack) => stack
3949+ case None => Stack [Type ]()
3950+
3951+ println(s " Scrutinee ${scrut.show}" )
3952+ println(s " Reduction stack: ${reductionStatus.map(_.show)}" )
3953+
3954+ if reductionStatus.contains(tp) then
3955+ ErrorType (em " Cyclic match type reduction detected " )
3956+ else
3957+ val bodyType = {
3958+ reductionStatus.push(tp)
3959+ given Context = ctx.fresh.setProperty(Reduction , reductionStatus)
3960+ tp.simplified
3961+ }
3962+ bodyType
3963+
39443964 case MatchResult .ReducedAndDisjoint =>
39453965 // Empty types break the basic assumption that if a scrutinee and a
39463966 // pattern are disjoint it's OK to reduce passed that pattern. Indeed,
0 commit comments