@@ -1985,8 +1985,19 @@ object Types {
1985
1985
* except for replacing type parameters with associated type variables.
1986
1986
*/
1987
1987
def simplified (using Context ): Type =
1988
- // stripping LazyRef is important for the reduction of applied match types
1989
- // see the comment in matchCases/recur for more details
1988
+ // A recursive match type will have the recursive call
1989
+ // wrapped in a LazyRef. For example in i18175, the recursive calls
1990
+ // to IsPiped within the definition of IsPiped are all wrapped in LazyRefs.
1991
+ // In addition to that, TypeMaps, such as the one that backs TypeOps.simplify,
1992
+ // by default will rewrap a LazyRef when applying its function.
1993
+ // The result of those two things means that given a big enough input
1994
+ // that recursive enough times through one or multiple match types,
1995
+ // reducing and simplifying the result of the case bodies,
1996
+ // can end up with a large stack of directly-nested lazy refs.
1997
+ // And if that nesting level breaches `Config.LogPendingSubTypesThreshold`,
1998
+ // then TypeComparer will eventually start returning `false` for `isSubType`.
1999
+ // Or, under -Yno-deep-subtypes, start throwing AssertionErrors.
2000
+ // So, we eagerly strip that lazy ref here to avoid the stacking.
1990
2001
val tp = stripLazyRef
1991
2002
TypeOps .simplify(tp, null )
1992
2003
0 commit comments