Skip to content

Commit 0b52df2

Browse files
committed
Avoid crashing in LazyRef.ref when checking for cycles
Report a cycle instead
1 parent 4411811 commit 0b52df2

File tree

4 files changed

+24
-16
lines changed

4 files changed

+24
-16
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ object Mode {
4141
*/
4242
val TypevarsMissContext: Mode = newMode(4, "TypevarsMissContext")
4343

44+
/** Are we looking for cyclic references? */
4445
val CheckCyclic: Mode = newMode(5, "CheckCyclic")
4546

4647
/** We are in a pattern alternative */

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,7 +2680,7 @@ object Types {
26802680
}
26812681
}
26822682

2683-
case class LazyRef(private var refFn: Context ?=> Type, reportCycles: Boolean = false) extends UncachedProxyType with ValueType {
2683+
case class LazyRef(private var refFn: Context ?=> Type) extends UncachedProxyType with ValueType {
26842684
private var myRef: Type = null
26852685
private var computed = false
26862686

@@ -2689,7 +2689,7 @@ object Types {
26892689
if myRef == null then
26902690
// if errors were reported previously handle this by throwing a CyclicReference
26912691
// instead of crashing immediately. A test case is neg/i6057.scala.
2692-
assert(reportCycles || ctx.reporter.errorsReported)
2692+
assert(ctx.mode.is(Mode.CheckCyclic) || ctx.reporter.errorsReported)
26932693
throw CyclicReference(NoDenotation)
26942694
else
26952695
computed = true
@@ -4515,7 +4515,9 @@ object Types {
45154515
else defn.AnyType // dummy type in case of errors
45164516
def refineSelfType(selfType: Type) =
45174517
RefinedType(selfType, sym.name,
4518-
TypeAlias(LazyRef(force, reportCycles = true)))
4518+
TypeAlias(
4519+
withMode(Mode.CheckCyclic)(
4520+
LazyRef(force))))
45194521
cinfo.selfInfo match
45204522
case self: Type =>
45214523
cinfo.derivedClassInfo(

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -406,21 +406,19 @@ object Checking {
406406
for (parent <- parents; mbr <- parent.abstractTypeMembers if qualifies(mbr.symbol))
407407
yield mbr.name.asTypeName
408408

409-
for (name <- abstractTypeNames)
410-
try {
411-
val mbr = joint.member(name)
412-
mbr.info match {
413-
case bounds: TypeBounds =>
414-
!checkNonCyclic(mbr.symbol, bounds, reportErrors = true).isError
415-
case _ =>
416-
true
417-
}
418-
}
419-
catch {
420-
case ex: RecursionOverflow =>
409+
withMode(Mode.CheckCyclic) {
410+
for name <- abstractTypeNames do
411+
try
412+
val mbr = joint.member(name)
413+
mbr.info match
414+
case bounds: TypeBounds =>
415+
!checkNonCyclic(mbr.symbol, bounds, reportErrors = true).isError
416+
case _ =>
417+
true
418+
catch case _: RecursionOverflow | _: CyclicReference =>
421419
report.error(em"cyclic reference involving type $name", pos)
422420
false
423-
}
421+
}
424422
}
425423

426424
/** Check that symbol's definition is well-formed. */

tests/neg/i10256.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait Foo[T <: Foo[T]] {
2+
type I <: Foo[I]
3+
}
4+
5+
trait Bar[T <: Foo[T]] extends Foo[T] { // error: cyclic
6+
self: T =>
7+
}

0 commit comments

Comments
 (0)