Skip to content

Commit 633bb6a

Browse files
committed
Check inline expansion for exclusion
Preserve attachments of literal constant in `42: Unit`.
1 parent 13077f7 commit 633bb6a

File tree

2 files changed

+43
-29
lines changed

2 files changed

+43
-29
lines changed

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

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import util.common.*
3535
import util.{Property, SimpleIdentityMap, SrcPos}
3636
import Applications.{tupleComponentTypes, wrapDefs, defaultArgument}
3737

38-
import collection.mutable
38+
import collection.mutable, mutable.ListBuffer
3939
import Implicits.*
4040
import util.Stats.record
4141
import config.Printers.{gadts, typr}
@@ -207,7 +207,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
207207
* a reference for `m` is searched. `null` in all other situations.
208208
*/
209209
def findRef(name: Name, pt: Type, required: FlagSet, excluded: FlagSet, pos: SrcPos,
210-
altImports: mutable.ListBuffer[TermRef] | Null = null)(using Context): Type = {
210+
altImports: ListBuffer[TermRef] | Null = null)(using Context): Type = {
211211
val refctx = ctx
212212
val noImports = ctx.mode.is(Mode.InPackageClauseName)
213213
def suppressErrors = excluded.is(ConstructorProxy)
@@ -1124,7 +1124,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11241124
record("typedNumber")
11251125
val digits = tree.digits
11261126
val target = pt.dealias
1127-
def lit(value: Any) = Literal(Constant(value)).withSpan(tree.span)
1127+
def lit(value: Any) = Literal(Constant(value)).withSpan(tree.span).withAttachmentsFrom(tree)
11281128
try {
11291129
// Special case primitive numeric types
11301130
if (target.isRef(defn.IntClass) ||
@@ -1174,7 +1174,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11741174
}
11751175
var app: untpd.Tree = untpd.Apply(fromDigits, firstArg :: otherArgs)
11761176
if (ctx.mode.is(Mode.Pattern)) app = untpd.Block(Nil, app)
1177-
return typed(app, pt)
1177+
return typed(app, pt).withAttachmentsFrom(tree)
11781178
case _ =>
11791179
}
11801180
// Otherwise convert to Int or Double according to digits format
@@ -3490,7 +3490,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
34903490
else {
34913491
val app = typedApply(desugar.binop(l, op, r).withAttachmentsFrom(tree), pt)
34923492
if op.name.isRightAssocOperatorName && !ctx.mode.is(Mode.QuotedExprPattern) then
3493-
val defs = new mutable.ListBuffer[Tree]
3493+
val defs = ListBuffer.empty[Tree]
34943494
def lift(app: Tree): Tree = (app: @unchecked) match
34953495
case Apply(fn, args) =>
34963496
if (app.tpe.isError) app
@@ -3790,7 +3790,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
37903790
trees mapconserve (typed(_))
37913791

37923792
def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(using Context): (List[Tree], Context) = {
3793-
val buf = new mutable.ListBuffer[Tree]
3793+
val buf = ListBuffer.empty[Tree]
37943794
var enumContexts: SimpleIdentityMap[Symbol, Context] = SimpleIdentityMap.empty
37953795
val initialNotNullInfos = ctx.notNullInfos
37963796
// A map from `enum` symbols to the contexts enclosing their definitions
@@ -3834,7 +3834,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38343834
traverse(xtree :: rest)
38353835
case stat :: rest =>
38363836
val stat1 = typed(stat)(using ctx.exprContext(stat, exprOwner))
3837-
if !Linter.warnOnInterestingResultInStatement(stat1) then checkStatementPurity(stat1)(stat, exprOwner)
3837+
if !Linter.warnOnInterestingResultInStatement(stat1) then
3838+
checkStatementPurity(stat1)(stat, exprOwner, isUnitExpr = false)
38383839
buf += stat1
38393840
traverse(rest)(using stat1.nullableContext)
38403841
case nil =>
@@ -4041,7 +4042,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
40414042
def selectionProto = SelectionProto(tree.name, mbrProto, compat, privateOK = inSelect, tree.nameSpan)
40424043

40434044
def tryExtension(using Context): Tree =
4044-
val altImports = new mutable.ListBuffer[TermRef]()
4045+
val altImports = ListBuffer.empty[TermRef]
40454046
findRef(tree.name, WildcardType, ExtensionMethod, EmptyFlags, qual.srcPos, altImports) match
40464047
case ref: TermRef =>
40474048
def tryExtMethod(ref: TermRef)(using Context) =
@@ -4050,7 +4051,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
40504051
tryExtMethod(ref)
40514052
else
40524053
// Try all possible imports and collect successes and failures
4053-
val successes, failures = new mutable.ListBuffer[(Tree, TyperState)]
4054+
val successes, failures = ListBuffer.empty[(Tree, TyperState)]
40544055
for alt <- ref :: altImports.toList do
40554056
val nestedCtx = ctx.fresh.setNewTyperState()
40564057
val app = tryExtMethod(alt)(using nestedCtx)
@@ -4708,22 +4709,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
47084709
return readapt(tree.cast(captured))
47094710

47104711
// drop type if prototype is Unit
4711-
if (pt isRef defn.UnitClass) {
4712+
if pt.isRef(defn.UnitClass) then
47124713
// local adaptation makes sure every adapted tree conforms to its pt
47134714
// so will take the code path that decides on inlining
47144715
val tree1 = adapt(tree, WildcardType, locked)
47154716
checkStatementPurity(tree1)(tree, ctx.owner, isUnitExpr = true)
4716-
4717-
if ctx.settings.Whas.valueDiscard
4718-
&& !ctx.isAfterTyper
4719-
&& !tree.isInstanceOf[Inlined]
4720-
&& !isThisTypeResult(tree)
4721-
&& !isAscribedToUnit(tree)
4722-
then
4723-
report.warning(ValueDiscarding(tree.tpe), tree.srcPos)
4724-
4717+
checkValueDiscard(tree)
47254718
return tpd.Block(tree1 :: Nil, unitLiteral)
4726-
}
47274719

47284720
// convert function literal to SAM closure
47294721
tree match {
@@ -4981,10 +4973,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
49814973
typedExpr(cmp, defn.BooleanType)
49824974
case _ =>
49834975

4984-
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean = false)(using Context): Unit =
4976+
private def checkStatementPurity(tree: tpd.Tree)(original: untpd.Tree, exprOwner: Symbol, isUnitExpr: Boolean)(using Context): Unit =
49854977
if !tree.tpe.isErroneous
49864978
&& !ctx.isAfterTyper
4987-
&& !tree.isInstanceOf[Inlined]
49884979
&& isPureExpr(tree)
49894980
&& !isSelfOrSuperConstrCall(tree)
49904981
then tree match
@@ -4999,13 +4990,26 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
49994990
// sometimes we do not have the original anymore and use the transformed tree instead.
50004991
// But taken together, the two criteria are quite accurate.
50014992
missingArgs(tree, tree.tpe.widen)
5002-
case _ if tree.hasAttachment(AscribedToUnit) =>
5003-
// The tree was ascribed to `Unit` explicitly to silence the warning.
5004-
()
5005-
case _ if isUnitExpr =>
5006-
report.warning(PureUnitExpression(original, tree.tpe), original.srcPos)
5007-
case _ =>
5008-
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
4993+
case tree =>
4994+
val warnable = tree match
4995+
case inlined: Inlined => inlined.expansion
4996+
case tree => tree
4997+
// Check if the tree was ascribed to `Unit` explicitly to silence the warning.
4998+
if !isThisTypeResult(warnable) && !isAscribedToUnit(warnable) then
4999+
val msg =
5000+
if isUnitExpr then
5001+
PureUnitExpression(original, warnable.tpe)
5002+
else
5003+
PureExpressionInStatementPosition(original, exprOwner)
5004+
report.warning(msg, original.srcPos)
5005+
5006+
private def checkValueDiscard(tree: tpd.Tree)(using Context): Unit =
5007+
if ctx.settings.Whas.valueDiscard && !ctx.isAfterTyper then
5008+
val warnable = tree match
5009+
case inlined: Inlined => inlined.expansion
5010+
case tree => tree
5011+
if !isThisTypeResult(warnable) && !isAscribedToUnit(warnable) then
5012+
report.warning(ValueDiscarding(warnable.tpe), tree.srcPos)
50095013

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

tests/warn/i23018.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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

0 commit comments

Comments
 (0)