Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Wperformance lints for *Ref boxing and nonlocal return #9889

Merged
merged 6 commits into from Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.")
som-snytt marked this conversation as resolved.
Show resolved Hide resolved

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)
}