@@ -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