Skip to content

Commit d50a9bb

Browse files
committed
Further refactoring of stackoverflow handling
This now handles all errors from #4368 to #4372 and also #318.
1 parent 8cc0b81 commit d50a9bb

File tree

7 files changed

+69
-22
lines changed

7 files changed

+69
-22
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ class TypeApplications(val self: Type) extends AnyVal {
168168
* any type parameter that is-rebound by the refinement.
169169
*/
170170
final def typeParams(implicit ctx: Context): List[TypeParamInfo] = /*>|>*/ track("typeParams") /*<|<*/ {
171-
self match {
171+
try self match {
172172
case self: TypeRef =>
173173
val tsym = self.symbol
174174
if (tsym.isClass) tsym.typeParams
@@ -193,6 +193,9 @@ class TypeApplications(val self: Type) extends AnyVal {
193193
case _ =>
194194
Nil
195195
}
196+
catch {
197+
case ex: Throwable => handleRecursive("type parameters of", self.show, ex)
198+
}
196199
}
197200

198201
/** If `self` is a higher-kinded type, its type parameters, otherwise Nil */

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,11 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
121121
protected def isSubType(tp1: Type, tp2: Type, a: ApproxState): Boolean = {
122122
val saved = approx
123123
this.approx = a
124-
try recur(tp1, tp2) finally this.approx = saved
124+
try recur(tp1, tp2)
125+
catch {
126+
case ex: Throwable => handleRecursive("subtype", i"$tp1 <:< $tp2", ex, weight = 2)
127+
}
128+
finally this.approx = saved
125129
}
126130

127131
protected def isSubType(tp1: Type, tp2: Type): Boolean = isSubType(tp1, tp2, NoApprox)
@@ -161,7 +165,8 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
161165
try {
162166
pendingSubTypes += p
163167
firstTry
164-
} finally {
168+
}
169+
finally {
165170
pendingSubTypes -= p
166171
}
167172
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,15 @@ object Types {
652652
catch {
653653
case ex: Throwable =>
654654
core.println(s"findMember exception for $this member $name, pre = $pre, recCount = $recCount")
655-
throw new RecursionOverflow("find-member", pre, name, ex)
655+
656+
def showPrefixSafely(pre: Type)(implicit ctx: Context): String = pre.stripTypeVar match {
657+
case pre: TermRef => i"${pre.termSymbol.name}."
658+
case pre: TypeRef => i"${pre.typeSymbol.name}#"
659+
case pre: TypeProxy => showPrefixSafely(pre.underlying)
660+
case _ => if (pre.typeSymbol.exists) i"${pre.typeSymbol.name}#" else "."
661+
}
662+
663+
handleRecursive("find-member", i"${showPrefixSafely(pre)}$name", ex)
656664
}
657665
finally {
658666
if (recCount >= Config.LogPendingFindMemberThreshold)

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,25 @@ class VarianceChecker()(implicit ctx: Context) {
8282
* same is true of the parameters (ValDefs).
8383
*/
8484
def apply(status: Option[VarianceError], tp: Type): Option[VarianceError] = trace(s"variance checking $tp of $base at $variance", variances) {
85-
if (status.isDefined) status
86-
else tp match {
87-
case tp: TypeRef =>
88-
val sym = tp.symbol
89-
if (sym.variance != 0 && base.isContainedIn(sym.owner)) checkVarianceOfSymbol(sym)
90-
else if (sym.isAliasType) this(status, sym.info.bounds.hi)
91-
else foldOver(status, tp)
92-
case tp: MethodOrPoly =>
93-
this(status, tp.resultType) // params will be checked in their TypeDef or ValDef nodes.
94-
case AnnotatedType(_, annot) if annot.symbol == defn.UncheckedVarianceAnnot =>
95-
status
96-
//case tp: ClassInfo =>
97-
// ??? not clear what to do here yet. presumably, it's all checked at local typedefs
98-
case _ =>
99-
foldOver(status, tp)
85+
try
86+
if (status.isDefined) status
87+
else tp match {
88+
case tp: TypeRef =>
89+
val sym = tp.symbol
90+
if (sym.variance != 0 && base.isContainedIn(sym.owner)) checkVarianceOfSymbol(sym)
91+
else if (sym.isAliasType) this(status, sym.info.bounds.hi)
92+
else foldOver(status, tp)
93+
case tp: MethodOrPoly =>
94+
this(status, tp.resultType) // params will be checked in their TypeDef or ValDef nodes.
95+
case AnnotatedType(_, annot) if annot.symbol == defn.UncheckedVarianceAnnot =>
96+
status
97+
//case tp: ClassInfo =>
98+
// ??? not clear what to do here yet. presumably, it's all checked at local typedefs
99+
case _ =>
100+
foldOver(status, tp)
101+
}
102+
catch {
103+
case ex: Throwable => handleRecursive("variance check of", tp.show, ex)
100104
}
101105
}
102106

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ class CompilationTests extends ParallelTesting {
186186
compileFile("tests/neg-custom-args/noimports.scala", defaultOptions.and("-Yno-imports")) +
187187
compileFile("tests/neg-custom-args/noimports2.scala", defaultOptions.and("-Yno-imports")) +
188188
compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes) +
189+
compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes) +
189190
compileFile("tests/neg-custom-args/i1754.scala", allowDeepSubtypes) +
190191
compileFilesInDir("tests/neg-custom-args/isInstanceOf", allowDeepSubtypes and "-Xfatal-warnings") +
191192
compileFile("tests/neg-custom-args/i3627.scala", allowDeepSubtypes)

tests/neg-custom-args/i4372.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object i4372 {
2+
class X[A >: X[_ <: X[_]] <: X[A]]
3+
}

tests/neg/i4368.scala

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,16 @@ object Test7 {
106106
type Nat = Fix[Option]#T
107107
}
108108
}
109-
/*
110109
object Test8 {
111110

112111
class A {
113-
type T = B#U
112+
type T = B#U // error: cyclic
114113
}
115114

116115
class B {
117116
type U = A#T
118117
}
119118
}
120-
*/
121119
object Test9 {
122120
trait W {
123121
type A
@@ -147,4 +145,29 @@ object Test9 {
147145
// scalac reports a volatility error, but the dotty equivalent (checkRealizable)
148146
// is checked too late.
149147
}
148+
}
149+
object i4369 {
150+
trait X { self =>
151+
type R <: Z
152+
type Z >: X { type R = self.R; type Z = self.R }
153+
}
154+
class Foo extends X { type R = Foo; type Z = Foo } // error: too deep
155+
}
156+
object i4370 {
157+
class Foo { type R = A } // error: cyclic
158+
type A = List[Foo#R]
159+
}
160+
object i4371 {
161+
class Foo { type A = Boo#B } // error: cyclic
162+
class Boo { type B = Foo#A }
163+
}
164+
object i318 {
165+
trait Y {
166+
type A <: { type T >: B }
167+
type B >: { type T >: A }
168+
}
169+
170+
val y: Y = ???
171+
val a: y.A = ??? // error: too deep
172+
val b: y.B = a // error: too deep
150173
}

0 commit comments

Comments
 (0)