Skip to content

Commit

Permalink
-Wperformance lints *Ref boxing and nonlocal return
Browse files Browse the repository at this point in the history
-Xlint:nonlocal-return is supported for compatibility.
  • Loading branch information
hrhino authored and som-snytt committed Jan 2, 2022
1 parent 4b2151c commit de70802
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 23 deletions.
19 changes: 17 additions & 2 deletions src/compiler/scala/tools/nsc/settings/Warnings.scala
Expand Up @@ -98,7 +98,7 @@ trait Warnings {
|to prevent the shell from expanding patterns.""".stripMargin),
prepend = true)

// Non-lint warnings. -- TODO turn into MultiChoiceEnumeration
// Non-lint warnings.
val warnMacros = ChoiceSetting(
name = "-Wmacros",
helpArg = "mode",
Expand All @@ -117,6 +117,20 @@ trait Warnings {
val warnNumericWiden = BooleanSetting("-Wnumeric-widen", "Warn when numerics are widened.") withAbbreviation "-Ywarn-numeric-widen"
val warnOctalLiteral = BooleanSetting("-Woctal-literal", "Warn on obsolete octal syntax.") withAbbreviation "-Ywarn-octal-literal"

object PerformanceWarnings extends MultiChoiceEnumeration {
val Captured = Choice("captured", "Modification of var in closure causes boxing.")
val NonlocalReturn = Choice("nonlocal-return", "A return statement used an exception for flow control.")
}
val warnPerformance = MultiChoiceSetting(
name = "-Wperformance",
helpArg = "warning",
descr = "Enable or disable specific lints for performance",
domain = PerformanceWarnings,
default = Some(List("_"))
)
def warnCaptured = warnPerformance.contains(PerformanceWarnings.Captured)
def warnNonlocalReturn = warnPerformance.contains(PerformanceWarnings.NonlocalReturn)

object UnusedWarnings extends MultiChoiceEnumeration {
val Imports = Choice("imports", "Warn if an import selector is not referenced.")
val PatVars = Choice("patvars", "Warn if a variable bound in a pattern is unused.")
Expand Down Expand Up @@ -215,7 +229,6 @@ trait Warnings {
def warnStarsAlign = lint contains StarsAlign
def warnConstant = lint contains Constant
def lintUnused = lint contains Unused
def warnNonlocalReturn = lint contains NonlocalReturn
def lintImplicitNotFound = lint contains ImplicitNotFound
def warnSerialization = lint contains Serial
def lintValPatterns = lint contains ValPattern
Expand All @@ -239,6 +252,8 @@ trait Warnings {
if (s contains Unused) warnUnused.enable(UnusedWarnings.Linted)
else warnUnused.disable(UnusedWarnings.Linted)
if (s.contains(Deprecation) && deprecation.isDefault) deprecation.value = true
if (s.contains(NonlocalReturn)) warnPerformance.enable(PerformanceWarnings.NonlocalReturn)
else warnPerformance.disable(PerformanceWarnings.NonlocalReturn)
}

// Backward compatibility.
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/scala/tools/nsc/transform/LambdaLift.scala
Expand Up @@ -505,6 +505,9 @@ abstract class LambdaLift extends InfoTransform {
}
}

if (settings.warnCaptured)
reporter.warning(tree.pos, s"Modification of variable $name within a closure causes it to be boxed.")

treeCopy.ValDef(tree, mods, name, tpt1, factoryCall)
} else tree
case Return(Block(stats, value)) =>
Expand Down
2 changes: 1 addition & 1 deletion test/files/neg/t10820-warn.scala
@@ -1,4 +1,4 @@
// scalac: -Xfatal-warnings -Xlint:nonlocal-return
// scalac: -Werror -Wperformance
//

import util.Try
Expand Down
9 changes: 9 additions & 0 deletions test/files/neg/xlint-captured.check
@@ -0,0 +1,9 @@
xlint-captured.scala:10: warning: return statement uses an exception to pass control to the caller of the enclosing named method f
def f(): Unit = List(42).foreach(i => if (i > 27) return)
^
xlint-captured.scala:5: warning: Modification of variable c within a closure causes it to be boxed.
var c = a // nok
^
error: No warnings can be incurred under -Werror.
2 warnings
1 error
11 changes: 11 additions & 0 deletions test/files/neg/xlint-captured.scala
@@ -0,0 +1,11 @@
// scalac: -Werror -Wperformance
object Test {
var a, b = 0 // ok
def mkStrangeCounter(): Int => Int = {
var c = a // nok
object _d { var d = b }; import _d._ // ok
e => { c += a; d += b; a *= b; b -= c; c ^ d }
}

def f(): Unit = List(42).foreach(i => if (i > 27) return)
}
1 change: 0 additions & 1 deletion test/files/run/nonlocalreturn.check

This file was deleted.

4 changes: 1 addition & 3 deletions test/files/run/nonlocalreturn.scala
Expand Up @@ -6,9 +6,7 @@ object Test {
wrap({ return Some(1) ; None })
}

def main(args: Array[String]): Unit = {
println(f())
}
def main(args: Array[String]): Unit = assert(f() == Some(1))
}
// java.lang.ClassCastException: scala.Some cannot be cast to scala.None$
// at Test$$anonfun$f$1.apply(nonlocalreturn.scala:5)
Expand Down
1 change: 0 additions & 1 deletion test/files/run/retclosure.check

This file was deleted.

4 changes: 1 addition & 3 deletions test/files/run/retclosure.scala
Expand Up @@ -17,7 +17,5 @@ object Test {
}
}

def main(args: Array[String]): Unit = {
Console.println(response)
}
def main(args: Array[String]): Unit = assert(response == "check failed: some problem")
}
2 changes: 0 additions & 2 deletions test/files/run/spec-nlreturn.check

This file was deleted.

16 changes: 6 additions & 10 deletions test/files/run/spec-nlreturn.scala
@@ -1,17 +1,13 @@
//scalac: -Xlint:-nonlocal-return
object Test {
def f(): Int = {
try {
val g = (1 to 10 map { i => return 16 ; i }).sum
g
}
catch { case x: runtime.NonLocalReturnControl[_] =>
println(x.getClass.getName)
x.value.asInstanceOf[Int]
try (1 to 10).map { i => return 16 ; i }.sum
catch {
case x: runtime.NonLocalReturnControl[_] =>
assert(x.getClass.getName == "scala.runtime.NonLocalReturnControl$mcI$sp")
x.value.asInstanceOf[Int]
}
}

def main(args: Array[String]): Unit = {
println(f())
}
def main(args: Array[String]): Unit = assert(f() == 16)
}

0 comments on commit de70802

Please sign in to comment.