From f805cf526abb4343990ed31db6c63436d6fe4fde Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 6 Jul 2016 16:00:06 -0700 Subject: SI-9847 Nuance pure expr statement warning Clarify the current warning, which means that an expression split over multiple lines may not be parsed as naively expected. When typing a block, attempt minor nuance. For instance, a single expression is not in need of parens. Try to avoid duplicate warnings for expressions that were adapted away from result position. --- .../scala/tools/nsc/typechecker/Typers.scala | 41 +++++++++++++++++----- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9fa3564b2b..6b0bd98f8f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2413,13 +2413,36 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } val stats1 = if (isPastTyper) block.stats else - block.stats.flatMap(stat => stat match { + block.stats.flatMap { case vd@ValDef(_, _, _, _) if vd.symbol.isLazy => namer.addDerivedTrees(Typer.this, vd) - case _ => stat::Nil - }) - val stats2 = typedStats(stats1, context.owner) + case stat => stat::Nil + } + val stats2 = typedStats(stats1, context.owner, warnPure = false) val expr1 = typed(block.expr, mode &~ (FUNmode | QUALmode), pt) + + // sanity check block for unintended expr placement + if (!isPastTyper) { + val (count, result0, adapted) = + expr1 match { + case Block(expr :: Nil, Literal(Constant(()))) => (1, expr, true) + case Literal(Constant(())) => (0, EmptyTree, false) + case _ => (1, EmptyTree, false) + } + def checkPure(t: Tree, supple: Boolean): Unit = + if (treeInfo.isPureExprForWarningPurposes(t)) { + val msg = "a pure expression does nothing in statement position" + val parens = if (stats2.length + count > 1) "multiline expressions might require enclosing parentheses" else "" + val discard = if (adapted) "; a value can be silently discarded when Unit is expected" else "" + val text = + if (supple) s"${parens}${discard}" + else if (!parens.isEmpty) s"${msg}; ${parens}" else msg + context.warning(t.pos, text) + } + stats2.foreach(checkPure(_, supple = false)) + if (result0.nonEmpty) checkPure(result0, supple = true) + } + treeCopy.Block(block, stats2, expr1) .setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst) } finally { @@ -2994,7 +3017,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case _ => log("unhandled import: "+imp+" in "+unit); imp } - def typedStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { + def typedStats(stats: List[Tree], exprOwner: Symbol, warnPure: Boolean = true): List[Tree] = { val inBlock = exprOwner == context.owner def includesTargetPos(tree: Tree) = tree.pos.isRange && context.unit.exists && (tree.pos includes context.unit.targetPos) @@ -3025,9 +3048,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper ConstructorsOrderError(stat) } } - if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos, - "a pure expression does nothing in statement position; you may be omitting necessary parentheses" - ) + if (warnPure && !isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) { + val msg = "a pure expression does nothing in statement position" + val clause = if (stats.lengthCompare(1) > 0) "; multiline expressions may require enclosing parentheses" else "" + context.warning(stat.pos, s"${msg}${clause}") + } result } -- cgit v1.2.3