Skip to content

Commit ca8dbaf

Browse files
committed
Merge branch 'feature/linter/unused' of github.com:PaulCoral/dotty into feature/linter/unused
2 parents 8a91af1 + 2ed1f1f commit ca8dbaf

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import dotty.tools.dotc.typer.ImportInfo
1616
import dotty.tools.dotc.util.Property
1717
import dotty.tools.dotc.transform.CheckUnused.UnusedData.UnusedResult
1818
import dotty.tools.dotc.core.Mode
19+
import dotty.tools.dotc.core.Types.TypeTraverser
20+
import dotty.tools.dotc.core.Types.Type
21+
import dotty.tools.dotc.core.Types.AnnotatedType
22+
import dotty.tools.dotc.core.Flags.flagsString
23+
import dotty.tools.dotc.core.Flags
1924

2025

2126

@@ -64,13 +69,14 @@ class CheckUnused extends Phase:
6469
tree match
6570
case imp:tpd.Import =>
6671
unusedDataApply(_.registerImport(imp))
72+
traverseChildren(tree)(using newCtx)
6773
case ident: Ident =>
6874
unusedDataApply(_.registerUsed(ident.symbol))
6975
traverseChildren(tree)(using newCtx)
7076
case sel: Select =>
7177
unusedDataApply(_.registerUsed(sel.symbol))
7278
traverseChildren(tree)(using newCtx)
73-
case _: (tpd.Block | tpd.Template) =>
79+
case _: (tpd.Block | tpd.Template | tpd.PackageDef) =>
7480
unusedDataApply { ud =>
7581
ud.inNewScope(ScopeType.fromTree(tree))(traverseChildren(tree)(using newCtx))
7682
}
@@ -83,11 +89,19 @@ class CheckUnused extends Phase:
8389
case t: tpd.Bind =>
8490
unusedDataApply(_.registerPatVar(t))
8591
traverseChildren(tree)(using newCtx)
92+
case t@tpd.TypeTree() =>
93+
typeTraverser(unusedDataApply).traverse(t.tpe)
94+
traverseChildren(tree)(using newCtx)
8695
case _ =>
8796
traverseChildren(tree)(using newCtx)
8897
end traverse
8998
end traverser
9099

100+
private def typeTraverser(dt: (UnusedData => Any) => Unit)(using Context) = new TypeTraverser:
101+
override def traverse(tp: Type): Unit = tp match
102+
case AnnotatedType(_, annot) => dt(_.registerUsed(annot.symbol))
103+
case _ => traverseChildren(tp)
104+
91105
private def reportUnused(res: UnusedData.UnusedResult)(using Context): Unit =
92106
import CheckUnused.WarnTypes
93107
res.warnings.foreach { s =>
@@ -185,6 +199,8 @@ object CheckUnused:
185199
if !isConstructorOfSynth(sym) then
186200
usedInScope.top += sym -> sym.isAccessibleAsIdent
187201
usedDef += sym
202+
if sym.isConstructor && sym.exists then
203+
registerUsed(sym.owner) // constructor are "implicitly" imported with the class
188204

189205
/** Register a list of found (used) symbols */
190206
def registerUsed(syms: Seq[Symbol])(using Context): Unit =
@@ -340,10 +356,10 @@ object CheckUnused:
340356
/** Given an import and accessibility, return an option of selector that match import<->symbol */
341357
def isInImport(imp: tpd.Import, isAccessible: Boolean)(using Context): Option[ImportSelector] =
342358
val tpd.Import(qual, sels) = imp
343-
val qualHasSymbol = qual.tpe.member(sym.name).symbol == sym
359+
val qualHasSymbol = qual.tpe.member(sym.name).alternatives.map(_.symbol).contains(sym)
344360
def selector = sels.find(sel => sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name)
345361
def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven) || sym.is(Implicit)))
346-
if qualHasSymbol && !isAccessible then
362+
if qualHasSymbol && !isAccessible && sym.exists then
347363
selector.orElse(wildcard) // selector with name or wildcard (or given)
348364
else
349365
None

tests/neg-custom-args/fatal-warnings/i15503a.scala

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,53 @@ object Scala2ImplicitsGiven:
187187
val b = summon[Int]
188188
object G:
189189
import A.x // error
190-
val b = 1
190+
val b = 1
191+
192+
// -------------------------------------
193+
object TestNewKeyword:
194+
object Foo:
195+
class Aa[T](val x: T)
196+
object Bar:
197+
import Foo.Aa // OK
198+
val v = 1
199+
val a = new Aa(v)
200+
201+
// -------------------------------------
202+
object testAnnotatedType:
203+
import annotation.switch // OK
204+
val a = (??? : @switch) match
205+
case _ => ???
206+
207+
208+
//-------------------------------------
209+
package testImportsInImports:
210+
package a:
211+
package b:
212+
val x = 1
213+
package c:
214+
import a.b // OK
215+
import b.x // OK
216+
val y = x
217+
218+
//-------------------------------------
219+
package testOnOverloadedMethodsImports:
220+
package a:
221+
trait A
222+
trait B
223+
trait C:
224+
def foo(x: A):A = ???
225+
def foo(x: B):B = ???
226+
package b:
227+
object D extends a.C
228+
package c:
229+
import b.D.foo // error
230+
package d:
231+
import b.D.foo // OK
232+
def bar = foo((??? : a.A))
233+
package e:
234+
import b.D.foo // OK
235+
def bar = foo((??? : a.B))
236+
package f:
237+
import b.D.foo // OK
238+
def bar = foo((??? : a.A))
239+
def baz = foo((??? : a.B))

0 commit comments

Comments
 (0)