Skip to content

Inconsistent behavior of -Ywarn-value-discard flag #11379

@ChernikovP

Description

@ChernikovP

It looks like -Ywarn-value-discard flag doesn't always warn on value discarding:

bos-pchernikov-mac:personal pchernikov$ cat UnitOfTrust.scala 
object UnitOfTrust {
  import scala.util._

  private def unitRight[A]: Either[A, Unit] = Right(())

  // fails with:
  //   discarded non-Unit value
  // def test1: Either[Int, Unit] = Right(Right(()))
  // def test2: Either[Int, Unit] = Right(()).map(_ => unitRight[Int])
  // def test3: Either[Int, Unit] = Right(()).map { case _ => unitRight[Int] }

  // fails with:
  //   error: type mismatch;
  //   found   : scala.util.Right[Nothing,Unit]
  //   required: Unit => Unit
  // def test4: Either[Int, Unit] = Right(()).map(Right(()))

  // compiles just fine
  def test5: Either[Int, Unit] = Right(()).map { case _ => unitRight }
  def test6: Either[Int, Unit] = Right(()).map { _ => unitRight }
  def test7: Either[Int, Unit] = Right(()).map(_ => unitRight)
}

scalac output:

bos-pchernikov-mac:personal pchernikov$ ~/Downloads/scala-2.12.8/bin/scalac -Ywarn-value-discard -Xfatal-warnings -print UnitOfTrust.scala
[[syntax trees at end of                   cleanup]] // UnitOfTrust.scala
package <empty> {
  object UnitOfTrust extends Object {
    private def unitRight(): scala.util.Either = new scala.util.Right(scala.runtime.BoxedUnit.UNIT);
    def test5(): scala.util.Either = new scala.util.Right(scala.runtime.BoxedUnit.UNIT).map({
      ((x0$1: scala.runtime.BoxedUnit) => UnitOfTrust.this.$anonfun$test5$1(x0$1))
    });
    def test6(): scala.util.Either = new scala.util.Right(scala.runtime.BoxedUnit.UNIT).map({
      ((x$1: scala.runtime.BoxedUnit) => UnitOfTrust.this.$anonfun$test6$1(x$1))
    });
    def test7(): scala.util.Either = new scala.util.Right(scala.runtime.BoxedUnit.UNIT).map({
      ((x$2: scala.runtime.BoxedUnit) => UnitOfTrust.this.$anonfun$test7$1(x$2))
    });
    final <artifact> private[this] def $anonfun$test5$1(x0$1: scala.runtime.BoxedUnit): Unit = {
      case <synthetic> val x1: scala.runtime.BoxedUnit = x0$1;
      case4(){
        matchEnd3({
          UnitOfTrust.unitRight();
          scala.runtime.BoxedUnit.UNIT
        })
      };
      matchEnd3(x: scala.runtime.BoxedUnit){
        ()
      }
    };
    final <artifact> private[this] def $anonfun$test6$1(x$1: scala.runtime.BoxedUnit): Unit = {
      UnitOfTrust.unitRight();
      ()
    };
    final <artifact> private[this] def $anonfun$test7$1(x$2: scala.runtime.BoxedUnit): Unit = {
      UnitOfTrust.unitRight();
      ()
    };
    def <init>(): UnitOfTrust.type = {
      UnitOfTrust.super.<init>();
      ()
    }
  }
}

This may also have a regression from scala 2.11 to 2.12:

bos-pchernikov-mac:personal pchernikov$ cat UnitOfTrust2_11.scala
object UnitOfTrust {
  import scala.util._

  private def unitRight[A]: Either[A, Unit] = Right(())

  // fails with:
  //   discarded non-Unit value
  // def test1: Either[Int, Unit] = Right(Right(()))
  // def test2: Either[Int, Unit] = Right(()).right.map(_ => unitRight[Int])
  // def test3: Either[Int, Unit] = Right(()).right.map { case _ => unitRight[Int] }

  // fails with:
  //   error: type mismatch;
  //   found   : scala.util.Right[Nothing,Unit]
  //   required: Unit => Unit
  // def test4: Either[Int, Unit] = Right(()).right.map(Right(()))

  // compiles just fine
  def test5: Either[Int, Unit] = Right(()).right.map { case _ => unitRight }
  def test6: Either[Int, Unit] = Right(()).right.map { _ => unitRight }
  def test7: Either[Int, Unit] = Right(()).right.map(_ => unitRight)
}
bos-pchernikov-mac:personal pchernikov$ ~/Downloads/scala-2.11.12/bin/scalac -Ywarn-value-discard -Xfatal-warnings UnitOfTrust2_11.scala
bos-pchernikov-mac:personal pchernikov$

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions