diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 7cff6fa5f1f0..c547188c50a1 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -20,6 +20,7 @@ import dotty.tools.dotc.core.Types.{AnnotatedType, ConstantType, NoType, TermRef import dotty.tools.dotc.core.Flags.flagsString import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Names.Name +import dotty.tools.dotc.core.NameOps.isReplWrapperName import dotty.tools.dotc.transform.MegaPhase.MiniPhase import dotty.tools.dotc.core.Annotations import dotty.tools.dotc.core.Definitions @@ -423,9 +424,11 @@ object CheckUnused: def registerImport(imp: tpd.Import)(using Context): Unit = if !tpd.languageImport(imp.expr).nonEmpty && !imp.isGeneratedByEnum && !isTransparentAndInline(imp) then impInScope.top += imp - unusedImport ++= imp.selectors.filter { s => - !shouldSelectorBeReported(imp, s) && !isImportExclusion(s) && !isImportIgnored(imp, s) - } + if currScopeType.top != ScopeType.ReplWrapper then // #18383 Do not report top-level import's in the repl as unused + unusedImport ++= imp.selectors.filter { s => + !shouldSelectorBeReported(imp, s) && !isImportExclusion(s) && !isImportIgnored(imp, s) + } + end registerImport /** Register (or not) some `val` or `def` according to the context, scope and flags */ def registerDef(memDef: tpd.MemberDef)(using Context): Unit = @@ -794,12 +797,13 @@ object CheckUnused: enum ScopeType: case Local case Template + case ReplWrapper case Other object ScopeType: /** return the scope corresponding to the enclosing scope of the given tree */ - def fromTree(tree: tpd.Tree): ScopeType = tree match - case _:tpd.Template => Template + def fromTree(tree: tpd.Tree)(using Context): ScopeType = tree match + case tree: tpd.Template => if tree.symbol.name.isReplWrapperName then ReplWrapper else Template case _:tpd.Block => Local case _ => Other @@ -810,4 +814,3 @@ object CheckUnused: val Empty = UnusedResult(Set.empty) end CheckUnused - diff --git a/compiler/test-resources/repl/i18383 b/compiler/test-resources/repl/i18383 new file mode 100644 index 000000000000..81d3c9d5a7fd --- /dev/null +++ b/compiler/test-resources/repl/i18383 @@ -0,0 +1,14 @@ +scala>:settings -Wunused:all + +scala> import scala.collection.* + +scala> class Foo { import scala.util.*; println("foo") } +1 warning found +-- Warning: -------------------------------------------------------------------- +1 | class Foo { import scala.util.*; println("foo") } + | ^ + | unused import +// defined class Foo + +scala> { import scala.util.*; "foo" } +val res0: String = foo diff --git a/compiler/test/dotty/tools/repl/ReplCompilerTests.scala b/compiler/test/dotty/tools/repl/ReplCompilerTests.scala index ecae111604cf..67e63d0156a5 100644 --- a/compiler/test/dotty/tools/repl/ReplCompilerTests.scala +++ b/compiler/test/dotty/tools/repl/ReplCompilerTests.scala @@ -20,6 +20,14 @@ class ReplCompilerTests extends ReplTest: assertEquals("def foo: 1", storedOutput().trim) } + @Test def i18383NoWarnOnUnusedImport: Unit = { + initially { + run("import scala.collection.*") + } andThen { + println(lines().mkString("* ", "\n * ", "")) + } + } + @Test def compileTwo = initially { run("def foo: 1 = 1") @@ -509,4 +517,3 @@ class ReplHighlightTests extends ReplTest(ReplTest.defaultOptions.filterNot(_.st case class Tree(left: Tree, right: Tree) def deepTree(depth: Int): Tree deepTree(300)""") -