Skip to content

Commit 25ae174

Browse files
committed
Avoid overhead of dead code checking unless -Ywarn-dead-code is set
Initialization of the member module, `checkDead`, would create an empty mutable Stack, on each nested typer, which is wasteful. This commit creates two implementation of `CheckDead`. The no-op case is a shared singleton object.
1 parent 232d95a commit 25ae174

File tree

2 files changed

+55
-34
lines changed

2 files changed

+55
-34
lines changed

src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -575,40 +575,6 @@ trait TypeDiagnostics {
575575
}
576576
}
577577
}
578-
579-
object checkDead {
580-
private val exprStack: mutable.Stack[Symbol] = mutable.Stack(NoSymbol)
581-
// The method being applied to `tree` when `apply` is called.
582-
private def expr = exprStack.top
583-
584-
private def exprOK =
585-
(expr != Object_synchronized) &&
586-
!(expr.isLabel && treeInfo.isSynthCaseSymbol(expr)) // it's okay to jump to matchEnd (or another case) with an argument of type nothing
587-
588-
private def treeOK(tree: Tree) = {
589-
val isLabelDef = tree match { case _: LabelDef => true; case _ => false}
590-
tree.tpe != null && tree.tpe.typeSymbol == NothingClass && !isLabelDef
591-
}
592-
593-
@inline def updateExpr[A](fn: Tree)(f: => A) = {
594-
if (fn.symbol != null && fn.symbol.isMethod && !fn.symbol.isConstructor) {
595-
exprStack push fn.symbol
596-
try f finally exprStack.pop()
597-
} else f
598-
}
599-
def apply(tree: Tree): Tree = {
600-
// Error suppression (in context.warning) would squash some of these warnings.
601-
// It is presumed if you are using a -Y option you would really like to hear
602-
// the warnings you've requested; thus, use reporter.warning.
603-
if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK)
604-
reporter.warning(tree.pos, "dead code following this construct")
605-
tree
606-
}
607-
608-
// The checkDead call from typedArg is more selective.
609-
def inMode(mode: Mode, tree: Tree): Tree = if (mode.typingMonoExprByValue) apply(tree) else tree
610-
}
611-
612578
private def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
613579
private def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
614580

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,60 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
109109
private final val InterpolatorCodeRegex = """\$\{\s*(.*?)\s*\}""".r
110110
private final val InterpolatorIdentRegex = """\$[$\w]+""".r // note that \w doesn't include $
111111

112+
abstract sealed class CheckDead {
113+
def apply(tree: Tree): Tree
114+
@inline final def updateExpr[A](fn: Tree)(f: => A): A = {
115+
if (push(fn)) {
116+
try f finally pop()
117+
} else f
118+
}
119+
def push(fn: Tree): Boolean
120+
def pop(): Unit
121+
def inMode(mode: Mode, tree: Tree): Tree
122+
}
123+
object NoOpCheckDead extends CheckDead {
124+
def apply(tree: Tree): Tree = tree
125+
def push(fn: Tree): Boolean = false
126+
def pop(): Unit = ()
127+
def inMode(mode: Mode, tree: Tree): Tree = tree
128+
}
129+
class CheckingCheckDead() extends CheckDead {
130+
private val exprStack: mutable.Stack[Symbol] = mutable.Stack(NoSymbol)
131+
// The method being applied to `tree` when `apply` is called.
132+
private def expr = exprStack.top
133+
134+
private def exprOK =
135+
(expr != Object_synchronized) &&
136+
!(expr.isLabel && treeInfo.isSynthCaseSymbol(expr)) // it's okay to jump to matchEnd (or another case) with an argument of type nothing
137+
138+
private def treeOK(tree: Tree) = {
139+
val isLabelDef = tree match { case _: LabelDef => true; case _ => false}
140+
tree.tpe != null && tree.tpe.typeSymbol == NothingClass && !isLabelDef
141+
}
142+
143+
def push(fn: Tree): Boolean = {
144+
if (fn.symbol != null && fn.symbol.isMethod && !fn.symbol.isConstructor) {
145+
exprStack push fn.symbol
146+
true
147+
} else false
148+
}
149+
def pop(): Unit =
150+
exprStack.pop()
151+
152+
def apply(tree: Tree): Tree = {
153+
// Error suppression (in context.warning) would squash some of these warnings.
154+
// It is presumed if you are using a -Y option you would really like to hear
155+
// the warnings you've requested; thus, use reporter.warning.
156+
if (treeOK(tree) && exprOK)
157+
reporter.warning(tree.pos, "dead code following this construct")
158+
tree
159+
}
160+
161+
// The checkDead call from typedArg is more selective.
162+
def inMode(mode: Mode, tree: Tree): Tree = if (mode.typingMonoExprByValue) apply(tree) else tree
163+
}
164+
165+
112166
abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with PatternTyper with TyperContextErrors {
113167
import context0.unit
114168
import typeDebug.ptTree
@@ -253,6 +307,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
253307

254308
var context = context0
255309
def context1 = context
310+
private val checkDead: CheckDead = if (settings.warnDeadCode.value && context != null && context.unit.exists) new CheckingCheckDead() else NoOpCheckDead
256311

257312
// for use with silent type checking to when we can't have results with undetermined type params
258313
// note that this captures the context var

0 commit comments

Comments
 (0)