Skip to content

Commit b085760

Browse files
committed
Check inline expansion for exclusion
Preserve attachments of literal constant in `42: Unit`.
1 parent 73bbcfe commit b085760

File tree

3 files changed

+52
-24
lines changed

3 files changed

+52
-24
lines changed

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

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11571157
record("typedNumber")
11581158
val digits = tree.digits
11591159
val target = pt.dealias
1160-
def lit(value: Any) = Literal(Constant(value)).withSpan(tree.span)
1160+
def lit(value: Any) = Literal(Constant(value)).withSpan(tree.span).withAttachmentsFrom(tree)
11611161
try {
11621162
// Special case primitive numeric types
11631163
if (target.isRef(defn.IntClass) ||
@@ -1207,7 +1207,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12071207
}
12081208
var app: untpd.Tree = untpd.Apply(fromDigits, firstArg :: otherArgs)
12091209
if (ctx.mode.is(Mode.Pattern)) app = untpd.Block(Nil, app)
1210-
return typed(app, pt)
1210+
return typed(app, pt).withAttachmentsFrom(tree)
12111211
case _ =>
12121212
}
12131213
// Otherwise convert to Int or Double according to digits format
@@ -3994,7 +3994,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
39943994
traverse(xtree :: rest)
39953995
case stat :: rest =>
39963996
val stat1 = typed(stat)(using ctx.exprContext(stat, exprOwner))
3997-
if !Linter.warnOnInterestingResultInStatement(stat1) then checkStatementPurity(stat1)(stat, exprOwner)
3997+
if !Linter.warnOnInterestingResultInStatement(stat1) then
3998+
checkStatementPurity(stat1)(stat, exprOwner, isUnitExpr = false)
39983999
buf += stat1
39994000
traverse(rest)(using stat1.nullableContext)
40004001
case nil =>
@@ -4892,15 +4893,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
48924893
// so will take the code path that decides on inlining
48934894
val tree1 = adapt(tree, WildcardType, locked)
48944895
checkStatementPurity(tree1)(tree, ctx.owner, isUnitExpr = true)
4895-
4896-
if ctx.settings.Whas.valueDiscard
4897-
&& !ctx.isAfterTyper
4898-
&& !tree.isInstanceOf[Inlined]
4899-
&& !isThisTypeResult(tree)
4900-
&& !isAscribedToUnit(tree)
4901-
then
4902-
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
4903-
4896+
checkValueDiscard(tree)
49044897
return tpd.Block(tree1 :: Nil, unitLiteral)
49054898
end if
49064899

@@ -5161,11 +5154,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
51615154
typedExpr(cmp, defn.BooleanType)
51625155
case _ =>
51635156

5164-
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean = false)(using Context): Unit =
5157+
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean)
5158+
(using Context): Unit =
5159+
inline def isPureNotInlinedUnit = tree match
5160+
case Inlined(_, Nil, Literal(k)) if k.tag == UnitTag => false // assert(2 + 2 == 4)
5161+
case tree => isPureExpr(tree)
51655162
if !tree.tpe.isErroneous
51665163
&& !ctx.isAfterTyper
5167-
&& !tree.isInstanceOf[Inlined]
5168-
&& isPureExpr(tree)
5164+
&& isPureNotInlinedUnit
51695165
&& !isSelfOrSuperConstrCall(tree)
51705166
then tree match
51715167
case closureDef(meth)
@@ -5179,13 +5175,26 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
51795175
// sometimes we do not have the original anymore and use the transformed tree instead.
51805176
// But taken together, the two criteria are quite accurate.
51815177
missingArgs(tree, tree.tpe.widen)
5182-
case _ if tree.hasAttachment(AscribedToUnit) =>
5183-
// The tree was ascribed to `Unit` explicitly to silence the warning.
5184-
()
5185-
case _ if isUnitExpr =>
5186-
report.warning(PureUnitExpression(original, tree.tpe), original.srcPos)
5187-
case _ =>
5188-
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
5178+
case tree =>
5179+
val warnable = tree match
5180+
case inlined: Inlined => inlined.expansion
5181+
case tree => tree
5182+
// Check if the tree was ascribed to `Unit` explicitly to silence the warning.
5183+
if !isThisTypeResult(warnable) && !isAscribedToUnit(warnable) then
5184+
val msg =
5185+
if isUnitExpr then
5186+
PureUnitExpression(original, warnable.tpe)
5187+
else
5188+
PureExpressionInStatementPosition(original, exprOwner)
5189+
report.warning(msg, original.srcPos)
5190+
5191+
private def checkValueDiscard(tree: tpd.Tree)(using Context): Unit =
5192+
if ctx.settings.Whas.valueDiscard && !ctx.isAfterTyper then
5193+
val warnable = tree match
5194+
case inlined: Inlined => inlined.expansion
5195+
case tree => tree
5196+
if !isThisTypeResult(warnable) && !isAscribedToUnit(warnable) then
5197+
report.warning(ValueDiscarding(warnable.tpe), tree.srcPos)
51895198

51905199
/** Types the body Scala 2 macro declaration `def f = macro <body>` */
51915200
protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree =

tests/warn/i23018.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//> using options -Wvalue-discard
2+
3+
transparent inline def toto: Any = 1
4+
transparent inline def uhoh = 42: Unit // nowarn
5+
def tata: Unit = toto // warn pure Discard
6+
def hmm: Unit = uhoh
7+
def literally: Unit = 42 // warn pure Discard
8+
def funnily = 42: Unit // nowarn
9+
def impure = ("*" * 42).length
10+
def impurely: Unit = impure // warn impure discard
11+
12+
def i: Int = ???
13+
def parenthetically: Int =
14+
() // warn pure
15+
i
16+
transparent inline def reduced = ()
17+
def reductively: Int =
18+
reduced // no warn
19+
i

tests/warn/i23250.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//> using options -Wunused:all -Werror
1+
//> using options -Wunused:all
22

33
trait MonadError[F[_], E]
44
type MonadThrow[F[_]] = MonadError[F, Throwable]
@@ -10,7 +10,7 @@ trait WriteResult
1010
trait MetaStreamsSyntax:
1111
extension [F[_]](ms: MetaStreams[F])(using MonadThrow[F])
1212
def setMaxAge(): F[WriteResult] =
13-
summon[MonadThrow[F]]
13+
summon[MonadThrow[F]] // warn pure expr
1414
ms.use[WriteResult]
1515

1616
def setTruncateBefore(): F[WriteResult] =

0 commit comments

Comments
 (0)