From 4c58507151ccb4a358acec068fb309ade8652dbf Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 6 Jan 2025 15:22:30 -0800 Subject: [PATCH] Original of literal --- .../tools/dotc/transform/CheckUnused.scala | 9 ++++-- .../src/dotty/tools/dotc/typer/Typer.scala | 21 ++++++------ tests/warn/i17318.scala | 32 +++++++++++++++++++ 3 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 tests/warn/i17318.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 755bf5fd5b76..a5893d3fb030 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -16,7 +16,7 @@ import dotty.tools.dotc.report import dotty.tools.dotc.reporting.{CodeAction, UnusedSymbol} import dotty.tools.dotc.rewrites.Rewrites import dotty.tools.dotc.transform.MegaPhase.MiniPhase -import dotty.tools.dotc.typer.ImportInfo +import dotty.tools.dotc.typer.{ImportInfo, Typer} import dotty.tools.dotc.util.{Property, Spans, SrcPos}, Spans.Span import dotty.tools.dotc.util.Chars.{isLineBreakChar, isWhitespace} import dotty.tools.dotc.util.chaining.* @@ -40,9 +40,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha override def isRunnable(using Context): Boolean = super.isRunnable && ctx.settings.WunusedHas.any && !ctx.isJava override def prepareForUnit(tree: Tree)(using Context): Context = - val infos = tree.getAttachment(refInfosKey).getOrElse { + val infos = tree.getAttachment(refInfosKey).getOrElse: RefInfos().tap(tree.withAttachment(refInfosKey, _)) - } ctx.fresh.setProperty(refInfosKey, infos) override def transformUnit(tree: Tree)(using Context): tree.type = if phaseMode == PhaseMode.Report then @@ -68,6 +67,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha refUsage(tree.symbol) tree + override def transformLiteral(tree: Literal)(using Context): tree.type = + tree.getAttachment(Typer.AdaptedTree).foreach(transformAllDeep) + tree + override def prepareForCaseDef(tree: CaseDef)(using Context): Context = nowarner.traverse(tree.pat) ctx diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 8e3a77b41efd..0f1d6e638e80 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -84,6 +84,9 @@ object Typer { /** Indicates that an expression is explicitly ascribed to [[Unit]] type. */ val AscribedToUnit = new Property.StickyKey[Unit] + /** Tree adaptation lost fidelity; this attachment preserves the original tree. */ + val AdaptedTree = new Property.StickyKey[tpd.Tree] + /** An attachment on a Select node with an `apply` field indicating that the `apply` * was inserted by the Typer. */ @@ -4565,16 +4568,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer } /** Adapt an expression of constant type to a different constant type `tpe`. */ - def adaptConstant(tree: Tree, tpe: ConstantType): Tree = { - def lit = Literal(tpe.value).withSpan(tree.span) - tree match { - case Literal(c) => lit - case tree @ Block(stats, expr) => tpd.cpy.Block(tree)(stats, adaptConstant(expr, tpe)) - case tree => - if (isIdempotentExpr(tree)) lit // See discussion in phase Literalize why we demand isIdempotentExpr - else Block(tree :: Nil, lit) - } - } + def adaptConstant(tree: Tree, tpe: ConstantType): Tree = + def lit = Literal(tpe.value).withSpan(tree.span).withAttachment(AdaptedTree, tree) + tree match + case Literal(_) => lit + case tree @ Block(stats, expr) => tpd.cpy.Block(tree)(stats, adaptConstant(expr, tpe)) + case tree => + if isIdempotentExpr(tree) then lit // See discussion in phase FirstTransform why we demand isIdempotentExpr + else Block(tree :: Nil, lit) def toSAM(tree: Tree, samParent: Type): Tree = tree match { case tree: Block => tpd.cpy.Block(tree)(tree.stats, toSAM(tree.expr, samParent)) diff --git a/tests/warn/i17318.scala b/tests/warn/i17318.scala new file mode 100644 index 000000000000..2a534bdb396c --- /dev/null +++ b/tests/warn/i17318.scala @@ -0,0 +1,32 @@ + +//> using options -Wunused:all + +object events { + final val PollOut = 0x002 + transparent inline def POLLIN = 0x001 +} + +def withShort(v: Short): Unit = ??? +def withInt(v: Int): Unit = ??? + +def usage() = + import events.POLLIN // reports unused + def v: Short = POLLIN + println(v) + +def usage2() = + import events.POLLIN // reports unused + withShort(POLLIN) + +def usage3() = + import events.POLLIN // does not report unused + withInt(POLLIN) + +def usage4() = + import events.POLLIN // reports unused + withShort(POLLIN) + +def value = 42 +def withDouble(v: Double): Unit = ??? +def usage5() = withDouble(value) +def usage6() = withShort(events.POLLIN)