scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
232 stars 21 forks source link

-Ywarn-unused warns for vals in for comprehension,"local val... is never used" #9158

Closed scabug closed 7 years ago

scabug commented 9 years ago
$ cat unused.scala
object Unused {
  val optTup = Some((1, 2))

  for {
    tup <- optTup
    (num1, num2) = tup
  } yield (num1 + num2)
}
$ scalac -Ywarn-unused unused.scala
unused.scala:6: warning: local val in value $anonfun is never used
    (num1, num2) = tup
     ^
unused.scala:6: warning: local val in value $anonfun is never used
    (num1, num2) = tup
           ^
two warnings found
scabug commented 9 years ago

Imported From: https://issues.scala-lang.org/browse/SI-9158?orig=1 Reporter: Andrey Kuznetsov (prettynatty) Affected Versions: 2.11.5 See #7712

scabug commented 9 years ago

@retronym said: We removed this option from -Xlint in #7712 because, as you have found, it is somewhat incomplete.

scabug commented 9 years ago

@som-snytt said: One way to look at it is that the warning is there to keep you from doing something unintentional.

The warning is not spurious, in that the for comprehension desugars into an extra packaging step; it's the for comprehension equivalent of autoboxing.

http://stackoverflow.com/questions/14087014/what-are-the-scoping-rules-for-vals-in-scala-for-comprehensions

See the part where he goes, "Wait, really?" The locals in the yield block are unused.

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#for-comprehensions-and-for-loops

Intended:

  for {
    tup <- optTup
  } yield {
    val (num1, num2) = tup
    (num1 + num2)
  }
scabug commented 9 years ago

Andrey Kuznetsov (prettynatty) said (edited on Feb 18, 2015 9:55:45 PM UTC): But what if I want to write the something like this? Such code throws warning too.

  for {
    tup1 <- optTup
    (num1, num2) = tup1
    tup2 <- fn(num2, num1)
  } yield {
    tup2 // or anything else
  }

Is it really unintended?

scabug commented 9 years ago

@som-snytt said: Here is another example that could benefit from more efficient handling of intermediate results.

Because the unused extraction result i is not bundled in the tupling step, the extractor is invoked three times.

scala> for (s <- List("ab","abc") ; X(i) = s if i > 2) yield i // show
[snip]
      val res0 = List("ab", "abc").map(((s) => {
        <synthetic> <artifact> private[this] val x$2 = s: @scala.unchecked match {
          case (x$1 @ X((i @ _))) => scala.Tuple2(x$1, i)
        };
        val x$1 = x$2._1;
        val i = x$2._2;
        scala.Tuple2(s, x$1)
      })).withFilter(((x$3) => x$3: @scala.unchecked match {
        case scala.Tuple2((s @ _), X((i @ _))) => i > 2
      })).map(((x$4) => x$4: @scala.unchecked match {
        case scala.Tuple2((s @ _), X((i @ _))) => i
      }))
    }
  }
}
scabug commented 8 years ago

@som-snytt said: The PR tags the binds as if they were (i @ *, j @ *) = t which is the way to disable the warning in source.

https://github.com/scala/scala/pull/5402