Skip to content

Commit cf45fa2

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 1597d59 commit cf45fa2

File tree

2 files changed

+62
-34
lines changed

2 files changed

+62
-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
@@ -676,40 +676,6 @@ trait TypeDiagnostics {
676676
}
677677
}
678678
}
679-
680-
object checkDead {
681-
private val exprStack: mutable.Stack[Symbol] = mutable.Stack(NoSymbol)
682-
// The method being applied to `tree` when `apply` is called.
683-
private def expr = exprStack.top
684-
685-
private def exprOK =
686-
(expr != Object_synchronized) &&
687-
!(expr.isLabel && treeInfo.isSynthCaseSymbol(expr)) // it's okay to jump to matchEnd (or another case) with an argument of type nothing
688-
689-
private def treeOK(tree: Tree) = {
690-
val isLabelDef = tree match { case _: LabelDef => true; case _ => false}
691-
tree.tpe != null && tree.tpe.typeSymbol == NothingClass && !isLabelDef
692-
}
693-
694-
@inline def updateExpr[A](fn: Tree)(f: => A) = {
695-
if (fn.symbol != null && fn.symbol.isMethod && !fn.symbol.isConstructor) {
696-
exprStack push fn.symbol
697-
try f finally exprStack.pop()
698-
} else f
699-
}
700-
def apply(tree: Tree): Tree = {
701-
// Error suppression (in context.warning) would squash some of these warnings.
702-
// It is presumed if you are using a -Y option you would really like to hear
703-
// the warnings you've requested; thus, use reporter.warning.
704-
if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK)
705-
reporter.warning(tree.pos, "dead code following this construct")
706-
tree
707-
}
708-
709-
// The checkDead call from typedArg is more selective.
710-
def inMode(mode: Mode, tree: Tree): Tree = if (mode.typingMonoExprByValue) apply(tree) else tree
711-
}
712-
713679
private def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded
714680
private def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive"
715681

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

Lines changed: 62 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
@@ -254,6 +308,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
254308
var context = context0
255309
def context1 = context
256310

311+
private var _checkDead: CheckDead = _
312+
private def checkDead: CheckDead = {
313+
if (_checkDead == null) {
314+
_checkDead = if (settings.warnDeadCode.value && context != null && context.unit.exists) new CheckingCheckDead() else NoOpCheckDead
315+
}
316+
_checkDead
317+
}
318+
257319
// for use with silent type checking to when we can't have results with undetermined type params
258320
// note that this captures the context var
259321
val isMonoContext = (_: Any) => context.undetparams.isEmpty

0 commit comments

Comments
 (0)