diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 230aae668d0a..c59003c9a242 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1685,6 +1685,20 @@ class Global(var currentSettings: Settings, reporter0: LegacyReporter) } def createJavadoc = false + + var typerDepth: Int = 0 + var maxTyperDepth = 0 + final def decTyperDepth(): Unit = { + typerDepth -= 1 + } + final def incTyperDepth(): Unit = { + typerDepth += 1 + maxTyperDepth = math.max(typerDepth, maxTyperDepth) + } + val typerDepthReportThreshold: Int = Integer.getInteger("scala.typer.ast.depth.threshhold", Int.MaxValue) + scala.sys.addShutdownHook { + println("max typer depth: " + maxTyperDepth) + } } object Global { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index ae7813a96bd8..af10a93ef75c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -2015,8 +2015,12 @@ trait Namers extends MethodSynthesis { override def complete(sym: Symbol) = { lockedCount += 1 + val saved = typerDepth try completeImpl(sym) - finally lockedCount -= 1 + finally { + typerDepth = saved + lockedCount -= 1 + } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b572d37d2c31..f50787317337 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5633,6 +5633,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } def typed(tree: Tree, mode: Mode, pt: Type): Tree = { + incTyperDepth() + if (typerDepth > typerDepthReportThreshold) { + var pos = context.enclMethod.owner.pos + if (pos == NoPosition) + pos = tree.pos + reporter.warning(pos, "AST depth within " + context.owner.enclMethod.pos + " exceeds " + typerDepthReportThreshold + " at " + globalPhase.name ) + } lastTreeToTyper = tree val statsEnabled = StatisticsStatics.areSomeHotStatsEnabled() && statistics.areHotStatsLocallyEnabled val startByType = if (statsEnabled) statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null @@ -5707,6 +5714,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } finally { if (shouldPopTypingStack) typingStack.pop(tree) if (statsEnabled) statistics.popTimer(byTypeStack, startByType) + decTyperDepth() } }