Skip to content

Commit 4be1409

Browse files
oderskyBlaisorblade
authored andcommitted
Detect and flag deep findMember recursions
Deep findMember recursions can happen as a recult of illegal cyclic structures. I don't think there's a complete way to avoid these structures before the cyclic search can happen. So we now detect it by imposing a recursion limit (configurable, by default 100).
1 parent be6ae0e commit 4be1409

File tree

5 files changed

+11
-19
lines changed

5 files changed

+11
-19
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,6 @@ object Config {
184184
*/
185185
final val LogPendingFindMemberThreshold = 9
186186

187-
/** Maximal number of outstanding recursive calls to findMember before backing out
188-
* when findMemberLimit is set.
189-
*/
190-
final val PendingFindMemberLimit = LogPendingFindMemberThreshold * 4
191-
192187
/** When in IDE, turn StaleSymbol errors into warnings instead of crashing */
193188
final val ignoreStaleInIDE = true
194189
}

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class ScalaSettings extends Settings.SettingGroup {
6363
val Xhelp = BooleanSetting("-X", "Print a synopsis of advanced options.")
6464
val XnoForwarders = BooleanSetting("-Xno-forwarders", "Do not generate static forwarders in mirror classes.")
6565
val XminImplicitSearchDepth = IntSetting("-Xmin-implicit-search-depth", "Set number of levels of implicit searches undertaken before checking for divergence.", 5)
66-
val xmaxInlines = IntSetting("-Xmax-inlines", "Maximal number of successive inlines", 32)
66+
val XmaxInlines = IntSetting("-Xmax-inlines", "Maximal number of successive inlines", 32)
6767
val XmaxClassfileName = IntSetting("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, 72 to 255)
6868
val Xmigration = VersionSetting("-Xmigration", "Warn about constructs whose behavior may have changed since version.")
6969
val Xprint = PhasesSetting("-Xprint", "Print out program after")
@@ -74,6 +74,7 @@ class ScalaSettings extends Settings.SettingGroup {
7474
val XmainClass = StringSetting("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d <jar>)", "")
7575
val XnoValueClasses = BooleanSetting("-Xno-value-classes", "Do not use value classes. Helps debugging.")
7676
val XreplLineWidth = IntSetting("-Xrepl-line-width", "Maximal number of columns per line for REPL output", 390)
77+
val XmaxMemberRecursions = IntSetting("-Xmax-member-recursions", "Maximal number of recursive calls to find-member", 100)
7778
val XfatalWarnings = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.")
7879
val XverifySignatures = BooleanSetting("-Xverify-signatures", "Verify generic signatures in generated bytecode.")
7980

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,4 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
326326

327327
object TypeOps {
328328
@sharable var track = false // !!!DEBUG
329-
330-
/** When a property with this key is set in a context, it limits the number
331-
* of recursive member searches. If the limit is reached, findMember returns
332-
* NoDenotation.
333-
*/
334-
val findMemberLimit = new Property.Key[Unit]
335329
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,17 +666,15 @@ object Types {
666666

667667
val recCount = ctx.findMemberCount
668668
if (recCount >= Config.LogPendingFindMemberThreshold) {
669-
if (ctx.property(TypeOps.findMemberLimit).isDefined &&
670-
ctx.findMemberCount > Config.PendingFindMemberLimit)
671-
return NoDenotation
669+
if (ctx.findMemberCount > ctx.settings.XmaxMemberRecursions.value)
670+
throw new CyclicFindMember(pre, name)
672671
ctx.pendingMemberSearches = name :: ctx.pendingMemberSearches
673672
}
674673
ctx.findMemberCount = recCount + 1
675-
//assert(ctx.findMemberCount < 20)
676674
try go(this)
677675
catch {
678676
case ex: Throwable =>
679-
core.println(i"findMember exception for $this member $name, pre = $pre")
677+
core.println(s"findMember exception for $this member $name, pre = $pre, recCount = $recCount")
680678
throw ex // DEBUG
681679
}
682680
finally {
@@ -4581,6 +4579,10 @@ object Types {
45814579
if (ctx.debug) printStackTrace()
45824580
}
45834581

4582+
class CyclicFindMember(pre: Type, name: Name)(implicit ctx: Context) extends TypeError(
4583+
i"""member search with prefix $pre too deep.
4584+
|searches, from inner to outer: .${ctx.pendingMemberSearches}% .%""")
4585+
45844586
private def otherReason(pre: Type)(implicit ctx: Context): String = pre match {
45854587
case pre: ThisType if pre.cls.givenSelfType.exists =>
45864588
i"\nor the self type of $pre might not contain all transitive dependencies"

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,13 @@ object Inliner {
122122
* and body that replace it.
123123
*/
124124
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
125-
if (enclosingInlineds.length < ctx.settings.xmaxInlines.value) {
125+
if (enclosingInlineds.length < ctx.settings.XmaxInlines.value) {
126126
val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
127127
if (ctx.reporter.hasErrors) tree else new Inliner(tree, body).inlined(pt)
128128
}
129129
else errorTree(
130130
tree,
131-
i"""|Maximal number of successive inlines (${ctx.settings.xmaxInlines.value}) exceeded,
131+
i"""|Maximal number of successive inlines (${ctx.settings.XmaxInlines.value}) exceeded,
132132
|Maybe this is caused by a recursive inline method?
133133
|You can use -Xmax:inlines to change the limit."""
134134
)

0 commit comments

Comments
 (0)