From 9f08c98a6e801d4798cb5c3794cab23deb6d9eec Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 15 Dec 2010 08:11:41 +0000 Subject: Stops barking up the wrong tree with -Ywarn-dea... Stops barking up the wrong tree with -Ywarn-dead-code. The origin of its issues was twofold: 1) synchronized acts by-name without being by-name (ticket #4086) 2) warnings are swallowed if context.reportGeneralErrors is false Those two plus a dash of bitrot. In any case it's at its all time happiest now. It found all the dead code related fixes in this commit. Way to go, -Ywarn-dead-code! Review by odersky. --- src/compiler/scala/tools/ant/ScalaTool.scala | 1 - src/compiler/scala/tools/ant/Scalac.scala | 1 - .../scala/tools/nsc/symtab/Definitions.scala | 5 ++-- .../scala/tools/nsc/typechecker/Implicits.scala | 1 - .../scala/tools/nsc/typechecker/Infer.scala | 6 ---- .../tools/nsc/typechecker/TypeDiagnostics.scala | 32 ++++++++++++++++++++++ .../scala/tools/nsc/typechecker/Typers.scala | 16 ++++++++--- src/library/scala/io/BytePickle.scala | 4 +-- src/library/scala/mobile/Code.scala | 1 - src/library/scala/xml/dtd/Scanner.scala | 2 +- 10 files changed, 50 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/ant/ScalaTool.scala b/src/compiler/scala/tools/ant/ScalaTool.scala index e9bc4435e1..5ac0c90a76 100644 --- a/src/compiler/scala/tools/ant/ScalaTool.scala +++ b/src/compiler/scala/tools/ant/ScalaTool.scala @@ -100,7 +100,6 @@ class ScalaTool extends ScalaMatchingTask { (if (input != "") List(st) else Nil) else { buildError("Platform " + st + " does not exist.") - Nil } } } diff --git a/src/compiler/scala/tools/ant/Scalac.scala b/src/compiler/scala/tools/ant/Scalac.scala index 6c56ace9fe..fcf293fb2a 100644 --- a/src/compiler/scala/tools/ant/Scalac.scala +++ b/src/compiler/scala/tools/ant/Scalac.scala @@ -329,7 +329,6 @@ class Scalac extends ScalaMatchingTask with ScalacShared { (if (input != "") List(st) else Nil) else { buildError("Phase " + st + " in log does not exist.") - Nil } } } diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index ee0a0c4d81..5f9696c71d 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -382,8 +382,9 @@ trait Definitions extends reflect.generic.StandardDefinitions { def isSeqType(tp: Type) = cond(tp.normalize) { case TypeRef(_, SeqClass, List(tparam)) => true } - def seqType(arg: Type) = typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(arg)) - def arrayType(arg: Type) = typeRef(ArrayClass.typeConstructor.prefix, ArrayClass, List(arg)) + def seqType(arg: Type) = typeRef(SeqClass.typeConstructor.prefix, SeqClass, List(arg)) + def arrayType(arg: Type) = typeRef(ArrayClass.typeConstructor.prefix, ArrayClass, List(arg)) + def byNameType(arg: Type) = appliedType(ByNameParamClass.typeConstructor, List(arg)) def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 8de11943cf..c695f70871 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -351,7 +351,6 @@ self: Analyzer => case Some(pending) => // println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG throw DivergentImplicit - SearchFailure case None => try { context.openImplicits = (pt, tree.symbol) :: context.openImplicits diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 3ffe25c61c..26fb5148bf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1479,12 +1479,6 @@ trait Infer { protected def includeCondition(sym: Symbol): Boolean = true } - def checkDead(tree: Tree): Tree = { - if (settings.Ywarndeadcode.value && tree.tpe != null && tree.tpe.typeSymbol == NothingClass) - context.warning (tree.pos, "dead code following this construct") - tree - } - /* -- Overload Resolution ---------------------------------------------- */ /* diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 22a60a8abf..3de2f38d5d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -332,6 +332,38 @@ trait TypeDiagnostics { private def contextError(pos: Position, msg: String) = context.error(pos, msg) private def contextError(pos: Position, err: Throwable) = context.error(pos, err) + object checkDead { + private var expr: Symbol = NoSymbol + private def exprOK = expr != Object_synchronized + private def treeOK(tree: Tree) = tree.tpe != null && tree.tpe.typeSymbol == NothingClass + + def updateExpr(fn: Tree) = { + if (fn.symbol != null && fn.symbol.isMethod && !fn.symbol.isConstructor) + checkDead.expr = fn.symbol + } + def apply(tree: Tree): Tree = { + // Error suppression will squash some of these warnings unless we circumvent it. + // It is presumed if you are using a -Y option you would really like to hear + // the warnings you've requested. + if (settings.Ywarndeadcode.value && context.unit != null && treeOK(tree) && exprOK) { + val saved = context.reportGeneralErrors + try { + context.reportGeneralErrors = true + context.warning(tree.pos, "dead code following this construct") + } + finally context.reportGeneralErrors = saved + } + tree + } + + // The checkDead call from typedArg is more selective. + def inMode(mode: Int, tree: Tree): Tree = { + val modeOK = (mode & (EXPRmode | BYVALmode | POLYmode)) == (EXPRmode | BYVALmode) + if (modeOK) apply(tree) + else tree + } + } + def symWasOverloaded(sym: Symbol) = sym.owner.isClass && sym.owner.info.member(sym.name).isOverloaded def cyclicAdjective(sym: Symbol) = if (symWasOverloaded(sym)) "overloaded" else "recursive" diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 0f87d6ba33..c20732b2bc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1791,7 +1791,8 @@ trait Typers { self: Analyzer => if (meth.isPrimaryConstructor && meth.isClassConstructor && phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) computeParamAliases(meth.owner, vparamss1, rhs1) - if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass) rhs1 = checkDead(rhs1) + if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass) + rhs1 = checkDead(rhs1) if (phase.id <= currentRun.typerPhase.id && meth.owner.isClass && meth.paramss.exists(ps => ps.exists(_.hasDefaultFlag) && isRepeatedParamType(ps.last.tpe))) @@ -2206,9 +2207,9 @@ trait Typers { self: Analyzer => } def typedArg(arg: Tree, mode: Int, newmode: Int, pt: Type): Tree = { - val t = constrTyperIf((mode & SCCmode) != 0).typed(arg, mode & stickyModes | newmode, pt) - if ((newmode & BYVALmode) != 0) t - else checkDead(t) + val typedMode = mode & stickyModes | newmode + val t = constrTyperIf((mode & SCCmode) != 0).typed(arg, typedMode, pt) + checkDead.inMode(typedMode, t) } def typedArgs(args: List[Tree], mode: Int) = @@ -2301,6 +2302,7 @@ trait Typers { self: Analyzer => if (sym != NoSymbol) fun = adapt(fun setSymbol sym setType pre.memberType(sym), funMode(mode), WildcardType) } + fun.tpe match { case OverloadedType(pre, alts) => val undetparams = context.extractUndetparams() @@ -2427,6 +2429,12 @@ trait Typers { self: Analyzer => } else { val tparams = context.extractUndetparams() if (tparams.isEmpty) { // all type params are defined + // In order for checkDead not to be misled by the unfortunate special + // case of AnyRef#synchronized (which is implemented with signature T => T + // but behaves as if it were (=> T) => T) we need to know what is the actual + // target of a call. Since this information is no longer available from + // typedArg, it is recorded here. + checkDead.updateExpr(fun) val args1 = typedArgs(args, argMode(fun, mode), paramTypes, formals) // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case: // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo) diff --git a/src/library/scala/io/BytePickle.scala b/src/library/scala/io/BytePickle.scala index 3a51f2e0b8..97e3ff589d 100644 --- a/src/library/scala/io/BytePickle.scala +++ b/src/library/scala/io/BytePickle.scala @@ -144,7 +144,7 @@ object BytePickle { case Ref() => val res2 = unat.appU(res._2) // read location upe.get(res2._1) match { // lookup value in unpickler env - case None => throw new IllegalArgumentException("invalid unpickler environment"); return null + case None => throw new IllegalArgumentException("invalid unpickler environment") case Some(v) => return (v.asInstanceOf[a], new UnPicklerState(res2._2, upe)) } } @@ -153,7 +153,7 @@ object BytePickle { def ulift[t](x: t): PU[t] = new PU[t] { def appP(a: t, state: Array[Byte]): Array[Byte] = - if (x != a) { throw new IllegalArgumentException("value to be pickled (" + a + ") != " + x); state } + if (x != a) throw new IllegalArgumentException("value to be pickled (" + a + ") != " + x) else state; def appU(state: Array[Byte]) = (x, state) } diff --git a/src/library/scala/mobile/Code.scala b/src/library/scala/mobile/Code.scala index 677248aabb..e1d04eafa5 100644 --- a/src/library/scala/mobile/Code.scala +++ b/src/library/scala/mobile/Code.scala @@ -197,7 +197,6 @@ class Code(clazz: java.lang.Class[_]) { cs(0).newInstance("").asInstanceOf[AnyRef] } else { system.error("class " + clazz.getName() + " has no public constructor") - null } } } diff --git a/src/library/scala/xml/dtd/Scanner.scala b/src/library/scala/xml/dtd/Scanner.scala index 0b2daa3284..1ac3c0f24d 100644 --- a/src/library/scala/xml/dtd/Scanner.scala +++ b/src/library/scala/xml/dtd/Scanner.scala @@ -65,7 +65,7 @@ class Scanner extends Tokens with parsing.TokenTests { case ENDCH => END case _ => if (isNameStart(c)) name; // NAME - else { system.error("unexpected character:"+c); END } + else system.error("unexpected character:" + c) } final def name = { -- cgit v1.2.3