Skip to content

Commit bf50ebd

Browse files
Backport "Improve message for discarded pure non-Unit values" to LTS (#20731)
Backports #18723 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents b26ae8e + fb14996 commit bf50ebd

File tree

17 files changed

+155
-24
lines changed

17 files changed

+155
-24
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2380,12 +2380,22 @@ class MemberWithSameNameAsStatic()(using Context)
23802380
class PureExpressionInStatementPosition(stat: untpd.Tree, val exprOwner: Symbol)(using Context)
23812381
extends Message(PureExpressionInStatementPositionID) {
23822382
def kind = MessageKind.PotentialIssue
2383-
def msg(using Context) = "A pure expression does nothing in statement position; you may be omitting necessary parentheses"
2383+
def msg(using Context) = "A pure expression does nothing in statement position"
23842384
def explain(using Context) =
23852385
i"""The pure expression $stat doesn't have any side effect and its result is not assigned elsewhere.
23862386
|It can be removed without changing the semantics of the program. This may indicate an error."""
23872387
}
23882388

2389+
class PureUnitExpression(stat: untpd.Tree, tpe: Type)(using Context)
2390+
extends Message(PureUnitExpressionID) {
2391+
def kind = MessageKind.PotentialIssue
2392+
def msg(using Context) = i"Discarded non-Unit value of type ${tpe.widen}. You may want to use `()`."
2393+
def explain(using Context) =
2394+
i"""As this expression is not of type Unit, it is desugared into `{ $stat; () }`.
2395+
|Here the `$stat` expression is a pure statement that can be discarded.
2396+
|Therefore the expression is effectively equivalent to `()`."""
2397+
}
2398+
23892399
class UnqualifiedCallToAnyRefMethod(stat: untpd.Tree, method: Symbol)(using Context)
23902400
extends Message(UnqualifiedCallToAnyRefMethodID) {
23912401
def kind = MessageKind.PotentialIssue

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4127,7 +4127,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
41274127
// local adaptation makes sure every adapted tree conforms to its pt
41284128
// so will take the code path that decides on inlining
41294129
val tree1 = adapt(tree, WildcardType, locked)
4130-
checkStatementPurity(tree1)(tree, ctx.owner)
4130+
checkStatementPurity(tree1)(tree, ctx.owner, isUnitExpr = true)
41314131
if (!ctx.isAfterTyper && !tree.isInstanceOf[Inlined] && ctx.settings.WvalueDiscard.value && !isThisTypeResult(tree)) {
41324132
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
41334133
}
@@ -4424,7 +4424,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
44244424
else false
44254425
}
44264426

4427-
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol)(using Context): Unit =
4427+
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean = false)(using Context): Unit =
44284428
if !tree.tpe.isErroneous
44294429
&& !ctx.isAfterTyper
44304430
&& !tree.isInstanceOf[Inlined]
@@ -4442,6 +4442,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
44424442
// sometimes we do not have the original anymore and use the transformed tree instead.
44434443
// But taken together, the two criteria are quite accurate.
44444444
missingArgs(tree, tree.tpe.widen)
4445+
case _ if isUnitExpr =>
4446+
report.warning(PureUnitExpression(original, tree.tpe), original.srcPos)
44454447
case _ =>
44464448
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
44474449

compiler/test-resources/repl/nowarn.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ scala> def f = { 1; 2 }
2727
-- [E129] Potential Issue Warning: ---------------------------------------------
2828
1 | def f = { 1; 2 }
2929
| ^
30-
|A pure expression does nothing in statement position; you may be omitting necessary parentheses
30+
| A pure expression does nothing in statement position
3131
|
3232
| longer explanation available when compiling with `-explain`
3333
def f: Int

language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class DiagnosticsTest {
3030
|}"""
3131
.diagnostics(m1,
3232
(m1 to m2,
33-
"A pure expression does nothing in statement position; you may be omitting necessary parentheses",
33+
"A pure expression does nothing in statement position",
3434
Warning, Some(PureExpressionInStatementPositionID)))
3535

3636
@Test def diagnosticWorksheetPureExpression: Unit =

tests/neg-custom-args/captures/real-try.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
-- [E129] Potential Issue Warning: tests/neg-custom-args/captures/real-try.scala:30:4 ----------------------------------
1+
-- [E190] Potential Issue Warning: tests/neg-custom-args/captures/real-try.scala:30:4 ----------------------------------
22
30 | b.x
33
| ^^^
4-
| A pure expression does nothing in statement position; you may be omitting necessary parentheses
4+
| Discarded non-Unit value of type () -> Unit. You may want to use `()`.
55
|
66
| longer explanation available when compiling with `-explain`
77
-- Error: tests/neg-custom-args/captures/real-try.scala:12:2 -----------------------------------------------------------

tests/neg-macros/annot-suspend-cycle.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- [E129] Potential Issue Warning: tests/neg-macros/annot-suspend-cycle/Macro.scala:7:4 --------------------------------
22
7 | new Foo
33
| ^^^^^^^
4-
| A pure expression does nothing in statement position; you may be omitting necessary parentheses
4+
| A pure expression does nothing in statement position
55
|
66
| longer explanation available when compiling with `-explain`
77
Cyclic macro dependencies in tests/neg-macros/annot-suspend-cycle/Test.scala.

tests/neg/i18408a.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- [E103] Syntax Error: tests/neg/i18408a.scala:2:0 --------------------------------------------------------------------
2+
2 |fa(42) // error
3+
|^^
4+
|Illegal start of toplevel definition
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E190] Potential Issue Warning: tests/neg/i18408a.scala:3:15 --------------------------------------------------------
8+
3 |def test1 = fa(42)
9+
| ^^
10+
| Discarded non-Unit value of type Int. You may want to use `()`.
11+
|
12+
| longer explanation available when compiling with `-explain`
13+
-- [E129] Potential Issue Warning: tests/neg/i18408a.scala:4:16 --------------------------------------------------------
14+
4 |def test2 = fa({42; ()})
15+
| ^^
16+
| A pure expression does nothing in statement position
17+
|
18+
| longer explanation available when compiling with `-explain`

tests/neg/i18408a.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def fa(f: String ?=> Unit): Unit = ???
2+
fa(42) // error
3+
def test1 = fa(42)
4+
def test2 = fa({42; ()})

tests/neg/i18408b.check

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- [E103] Syntax Error: tests/neg/i18408b.scala:2:0 --------------------------------------------------------------------
2+
2 |fa(42) // error
3+
|^^
4+
|Illegal start of toplevel definition
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E190] Potential Issue Warning: tests/neg/i18408b.scala:3:15 --------------------------------------------------------
8+
3 |def test1 = fa(42)
9+
| ^^
10+
| Discarded non-Unit value of type Int. You may want to use `()`.
11+
|
12+
| longer explanation available when compiling with `-explain`
13+
-- [E129] Potential Issue Warning: tests/neg/i18408b.scala:4:16 --------------------------------------------------------
14+
4 |def test2 = fa({42; ()})
15+
| ^^
16+
| A pure expression does nothing in statement position
17+
|
18+
| longer explanation available when compiling with `-explain`

tests/neg/i18408b.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def fa(f: => Unit): Unit = ???
2+
fa(42) // error
3+
def test1 = fa(42)
4+
def test2 = fa({42; ()})

0 commit comments

Comments
 (0)