Skip to content

Commit 045027c

Browse files
committed
Handle AvoidMap recursions
Issue a diagnostic instead of crashing when there is a stack overflow Avoids the crash in the minimized version of #15365
1 parent cec9aa3 commit 045027c

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
lines changed

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

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -423,38 +423,42 @@ object TypeOps:
423423
sym.is(Package) || sym.isStatic && isStaticPrefix(pre.prefix)
424424
case _ => true
425425

426-
override def apply(tp: Type): Type = tp match
427-
case tp: TermRef
428-
if toAvoid(tp) =>
429-
tp.info.widenExpr.dealias match {
430-
case info: SingletonType => apply(info)
431-
case info => range(defn.NothingType, apply(info))
432-
}
433-
case tp: TypeRef if toAvoid(tp) =>
434-
tp.info match {
435-
case info: AliasingBounds =>
436-
apply(info.alias)
437-
case TypeBounds(lo, hi) =>
438-
range(atVariance(-variance)(apply(lo)), apply(hi))
439-
case info: ClassInfo =>
440-
range(defn.NothingType, apply(classBound(info)))
426+
override def apply(tp: Type): Type =
427+
try
428+
tp match
429+
case tp: TermRef
430+
if toAvoid(tp) =>
431+
tp.info.widenExpr.dealias match {
432+
case info: SingletonType => apply(info)
433+
case info => range(defn.NothingType, apply(info))
434+
}
435+
case tp: TypeRef if toAvoid(tp) =>
436+
tp.info match {
437+
case info: AliasingBounds =>
438+
apply(info.alias)
439+
case TypeBounds(lo, hi) =>
440+
range(atVariance(-variance)(apply(lo)), apply(hi))
441+
case info: ClassInfo =>
442+
range(defn.NothingType, apply(classBound(info)))
443+
case _ =>
444+
emptyRange // should happen only in error cases
445+
}
446+
case tp: ThisType =>
447+
// ThisType is only used inside a class.
448+
// Therefore, either they don't appear in the type to be avoided, or
449+
// it must be a class that encloses the block whose type is to be avoided.
450+
tp
451+
case tp: LazyRef =>
452+
if localParamRefs.contains(tp.ref) then tp
453+
else if isExpandingBounds then emptyRange
454+
else mapOver(tp)
455+
case tl: HKTypeLambda =>
456+
localParamRefs ++= tl.paramRefs
457+
mapOver(tl)
441458
case _ =>
442-
emptyRange // should happen only in error cases
443-
}
444-
case tp: ThisType =>
445-
// ThisType is only used inside a class.
446-
// Therefore, either they don't appear in the type to be avoided, or
447-
// it must be a class that encloses the block whose type is to be avoided.
448-
tp
449-
case tp: LazyRef =>
450-
if localParamRefs.contains(tp.ref) then tp
451-
else if isExpandingBounds then emptyRange
452-
else mapOver(tp)
453-
case tl: HKTypeLambda =>
454-
localParamRefs ++= tl.paramRefs
455-
mapOver(tl)
456-
case _ =>
457-
super.apply(tp)
459+
super.apply(tp)
460+
catch case ex: Throwable =>
461+
handleRecursive("traversing for avoiding local references", s"${tp.show}" , ex)
458462
end apply
459463

460464
/** Three deviations from standard derivedSelect:
@@ -498,6 +502,7 @@ object TypeOps:
498502
* this as Future Work™.
499503
*/
500504
def avoid(tp: Type, symsToAvoid: => List[Symbol])(using Context): Type = {
505+
println(i"WIDEN $tp with $symsToAvoid%, % in ${ctx.typerState.constraint}")
501506
val widenMap = new AvoidMap {
502507
@threadUnsafe lazy val forbidden = symsToAvoid.toSet
503508
def toAvoid(tp: NamedType) =
@@ -508,6 +513,7 @@ object TypeOps:
508513
case tp: TypeVar if mapCtx.typerState.constraint.contains(tp) =>
509514
val lo = TypeComparer.instanceType(
510515
tp.origin, fromBelow = variance > 0 || variance == 0 && tp.hasLowerBound)(using mapCtx)
516+
println(i"INST $tp to $lo")
511517
val lo1 = apply(lo)
512518
if (lo1 ne lo) lo1 else tp
513519
case _ =>
@@ -516,6 +522,7 @@ object TypeOps:
516522
}
517523

518524
widenMap(tp)
525+
.showing(i"DONE $tp")
519526
}
520527

521528
/** If `tpe` is of the form `p.x` where `p` refers to a package

tests/pos/i15365.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
trait Tagged[U]
2+
type WithTag[+TT, UU] = TT & Tagged[UU]
3+
4+
trait FromInput[Val]
5+
implicit def coercedScalaInput[Tc1]: FromInput[WithTag[Tc1, Int]] = ???
6+
implicit def optionInput[To](implicit ev: FromInput[To]): FromInput[Option[To]] = ???
7+
8+
trait WithoutInputTypeTags[TW]
9+
implicit def coercedOptArgTpe[Tc]: WithoutInputTypeTags[Option[WithTag[Tc, Int]]] = ???
10+
11+
trait InputType[+TI]
12+
class OptionInputType[TO](ofType: InputType[TO]) extends InputType[Option[TO]]
13+
14+
type Argument[TA]
15+
def argument[Ta](argumentType: InputType[Ta])(implicit fromInput: FromInput[Ta], res: WithoutInputTypeTags[Ta]): Argument[Option[Ta]] = ???
16+
17+
def test = argument(OptionInputType(??? : InputType[WithTag[Boolean, Int]])) :: Nil

0 commit comments

Comments
 (0)