Skip to content

Commit 9dc1404

Browse files
committed
Implement -Wvalue-discard warning
Warn when an expression `e` with non-Unit type is adapted by embedding it into a block `{ e; () }` because the expected type is Unit.
1 parent c93098b commit 9dc1404

File tree

5 files changed

+29
-0
lines changed

5 files changed

+29
-0
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ private sealed trait WarningSettings:
156156
self: SettingGroup =>
157157
val Whelp: Setting[Boolean] = BooleanSetting("-W", "Print a synopsis of warning options.")
158158
val XfatalWarnings: Setting[Boolean] = BooleanSetting("-Werror", "Fail the compilation if there are any warnings.", aliases = List("-Xfatal-warnings"))
159+
val YwarnValueDiscard: Setting[Boolean] = BooleanSetting("-Wvalue-discard", "Warn when non-Unit expression results are unused.", aliases = List("-Ywarn-value-discard"))
159160

160161
val Wunused: Setting[List[String]] = MultiChoiceSetting(
161162
name = "-Wunused",

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
184184
case ImplicitSearchTooLargeID // errorNumber: 168
185185
case TargetNameOnTopLevelClassID // errorNumber: 169
186186
case NotClassTypeID // errorNumber 170
187+
case ValueDiscardingID // errorNumber 171
187188

188189
def errorNumber = ordinal - 1
189190

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,3 +2535,9 @@ import cc.CaptureSet.IdentityCaptRefMap
25352535
extends TypeMsg(NotClassTypeID), ShowMatchTrace(tp):
25362536
def msg = ex"$tp is not a class type"
25372537
def explain = ""
2538+
2539+
class ValueDiscarding(tp: Type)(using Context)
2540+
extends Message(ValueDiscardingID):
2541+
def kind = MessageKind.PotentialIssue
2542+
def msg = em"discarded non-Unit value of type $tp"
2543+
def explain = ""

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3905,6 +3905,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
39053905
// so will take the code path that decides on inlining
39063906
val tree1 = adapt(tree, WildcardType, locked)
39073907
checkStatementPurity(tree1)(tree, ctx.owner)
3908+
if (!ctx.isAfterTyper && !tree.isInstanceOf[Inlined] && ctx.settings.YwarnValueDiscard.value) {
3909+
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
3910+
}
39083911
return tpd.Block(tree1 :: Nil, Literal(Constant(())))
39093912
}
39103913

tests/neg/warn-value-discard.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// scalac: -Wvalue-discard -Werror
2+
3+
import scala.util.{Either, Right, Left}
4+
5+
case class Failed(msg: String)
6+
7+
def doSomething(): Either[Failed, Unit] =
8+
Right(())
9+
10+
def log(): Either[Failed, Unit] =
11+
Left(Failed("whoops you should have flatMapped me"))
12+
13+
def singleExpr(): Either[Failed, Unit] =
14+
doSomething().map(_ => log()) // error
15+
16+
def block(): Either[Failed, Unit] = {
17+
doSomething().map(_ => log()) // error
18+
}

0 commit comments

Comments
 (0)