Skip to content

spurious "a pure expression does nothing" warning (awkward to suppress in 2.12, prone to occur in sbt builds) #12112

Closed as not planned
@eed3si9n

Description

@eed3si9n

reproduction steps

Scala 2.13.3 or 2.12.12 with fatal warnings.

The following code emulates build.sbt, but I'm seeing it in sbt code really sbt/sbt#5743, and I'm afraid others will run into this if we upgrade to Scala 2.12.12.

object Test extends AnyRef with App {
  lazy val task1 = new AnyRef {
    val value: Int = {
      println("flip pancake")
      0
    }
  }

  lazy val task2 = new AnyRef {
    val value: Int = {
      println("flop pancake")
      0
    }
  }

  def use() =
    try {
      task1.value
      task2.value
      ()
    } catch {
      case _: Throwable => ()
    }

  use()
}

problem

predef-unit.scala:20: warning: a pure expression does nothing in statement position; multiline expressions might require enclosing parentheses
      task1.value
            ^
predef-unit.scala:21: warning: a pure expression does nothing in statement position; multiline expressions might require enclosing parentheses
      task2.value
            ^
error: No warnings can be incurred under -Werror.
2 warnings
1 error

expectations

task1.value may look pure-looking from the compiler's point of view, but it's actually a macro, and it's not.
The reproduction above exploits a bug that @som-snytt pointed out that it's not checking full path for laziness, but I'm not sure if fixing that alone would fix the situation with sbt.

Maybe it would be better to put this warning behind a flag as an opt-in or turn it into Scalafix rule instead?

notes

In the recent releases of Scala, "a pure expression does nothing in statement position" has become more enthusiastic/accurate in its reach. Maybe because it moved to RefCheck in scala/scala#8995?

This seems to be a common occurrence since there are multiple PRs related to this:

People have suggested various creative solutions in reply to https://twitter.com/eed3si9n/status/1293272725415505921.

(compile.value, ())._2

locally { val _ = compile.value }

https://github.com/AVSystem/scala-commons/blob/87c92cfcf5cbbd183fe5d77a841352b4e58ece39/commons-core/src/main/scala/com/avsystem/commons/SharedExtensions.scala#L81

  class UniversalOps[A](private val a: A) extends AnyVal {
    /**
      * Explicit syntax to discard the value of a side-effecting expression.
      * Useful when `-Ywarn-value-discard` compiler option is enabled.
      */
    @silent
    def discard: Unit = ()
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions