Skip to content

Commit 82feb9b

Browse files
committed
Register usage of symbols in non-inferred type trees in CheckUnused
fixes lampepfl#16930
1 parent 0416992 commit 82feb9b

File tree

2 files changed

+54
-27
lines changed

2 files changed

+54
-27
lines changed

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

+32-27
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ class CheckUnused extends MiniPhase:
4646
*/
4747
private val _key = Property.Key[UnusedData]
4848

49-
extension (k: Property.Key[UnusedData])
50-
private def unusedDataApply[U](f: UnusedData => U)(using Context): Context =
51-
ctx.property(_key).foreach(f)
52-
ctx
53-
private def getUnusedData(using Context): Option[UnusedData] =
54-
ctx.property(_key)
49+
private def unusedDataApply[U](f: UnusedData => U)(using Context): Context =
50+
ctx.property(_key).foreach(f)
51+
ctx
52+
private def getUnusedData(using Context): Option[UnusedData] =
53+
ctx.property(_key)
5554

5655
override def phaseName: String = CheckUnused.phaseName
5756

@@ -71,7 +70,7 @@ class CheckUnused extends MiniPhase:
7170
// ========== END + REPORTING ==========
7271

7372
override def transformUnit(tree: tpd.Tree)(using Context): tpd.Tree =
74-
_key.unusedDataApply(ud => reportUnused(ud.getUnused))
73+
unusedDataApply(ud => reportUnused(ud.getUnused))
7574
tree
7675

7776
// ========== MiniPhase Prepare ==========
@@ -81,15 +80,15 @@ class CheckUnused extends MiniPhase:
8180
ctx
8281

8382
override def prepareForIdent(tree: tpd.Ident)(using Context): Context =
84-
if tree.symbol.exists then
85-
_key.unusedDataApply(_.registerUsed(tree.symbol, Some(tree.name)))
83+
if tree.symbol.exists then
84+
unusedDataApply(_.registerUsed(tree.symbol, Some(tree.name)))
8685
else if tree.hasType then
87-
_key.unusedDataApply(_.registerUsed(tree.tpe.classSymbol, Some(tree.name)))
86+
unusedDataApply(_.registerUsed(tree.tpe.classSymbol, Some(tree.name)))
8887
else
8988
ctx
9089

9190
override def prepareForSelect(tree: tpd.Select)(using Context): Context =
92-
_key.unusedDataApply(_.registerUsed(tree.symbol, Some(tree.name)))
91+
unusedDataApply(_.registerUsed(tree.symbol, Some(tree.name)))
9392

9493
override def prepareForBlock(tree: tpd.Block)(using Context): Context =
9594
pushInBlockTemplatePackageDef(tree)
@@ -101,33 +100,33 @@ class CheckUnused extends MiniPhase:
101100
pushInBlockTemplatePackageDef(tree)
102101

103102
override def prepareForValDef(tree: tpd.ValDef)(using Context): Context =
104-
_key.unusedDataApply{ud =>
103+
unusedDataApply{ud =>
105104
// do not register the ValDef generated for `object`
106105
if !tree.symbol.is(Module) then
107106
ud.registerDef(tree)
108107
ud.addIgnoredUsage(tree.symbol)
109108
}
110109

111110
override def prepareForDefDef(tree: tpd.DefDef)(using Context): Context =
112-
_key.unusedDataApply{ ud =>
111+
unusedDataApply{ ud =>
113112
import ud.registerTrivial
114113
tree.registerTrivial
115114
ud.registerDef(tree)
116115
ud.addIgnoredUsage(tree.symbol)
117116
}
118117

119118
override def prepareForTypeDef(tree: tpd.TypeDef)(using Context): Context =
120-
_key.unusedDataApply{ ud =>
119+
unusedDataApply{ ud =>
121120
if !tree.symbol.is(Param) then // Ignore type parameter (as Scala 2)
122121
ud.registerDef(tree)
123122
ud.addIgnoredUsage(tree.symbol)
124123
}
125124

126125
override def prepareForBind(tree: tpd.Bind)(using Context): Context =
127-
_key.unusedDataApply(_.registerPatVar(tree))
126+
unusedDataApply(_.registerPatVar(tree))
128127

129128
override def prepareForTypeTree(tree: tpd.TypeTree)(using Context): Context =
130-
typeTraverser(_key.unusedDataApply).traverse(tree.tpe)
129+
if !tree.isInstanceOf[tpd.InferredTypeTree] then typeTraverser(unusedDataApply).traverse(tree.tpe)
131130
ctx
132131

133132
// ========== MiniPhase Transform ==========
@@ -145,27 +144,27 @@ class CheckUnused extends MiniPhase:
145144
tree
146145

147146
override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree =
148-
_key.unusedDataApply(_.removeIgnoredUsage(tree.symbol))
147+
unusedDataApply(_.removeIgnoredUsage(tree.symbol))
149148
tree
150149

151150
override def transformDefDef(tree: tpd.DefDef)(using Context): tpd.Tree =
152-
_key.unusedDataApply(_.removeIgnoredUsage(tree.symbol))
151+
unusedDataApply(_.removeIgnoredUsage(tree.symbol))
153152
tree
154153

155154
override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree =
156-
_key.unusedDataApply(_.removeIgnoredUsage(tree.symbol))
155+
unusedDataApply(_.removeIgnoredUsage(tree.symbol))
157156
tree
158157

159158
// ---------- MiniPhase HELPERS -----------
160159

161160
private def pushInBlockTemplatePackageDef(tree: tpd.Block | tpd.Template | tpd.PackageDef)(using Context): Context =
162-
_key.unusedDataApply { ud =>
161+
unusedDataApply { ud =>
163162
ud.pushScope(UnusedData.ScopeType.fromTree(tree))
164163
}
165164
ctx
166165

167166
private def popOutBlockTemplatePackageDef()(using Context): Context =
168-
_key.unusedDataApply { ud =>
167+
unusedDataApply { ud =>
169168
ud.popScope()
170169
}
171170
ctx
@@ -188,7 +187,7 @@ class CheckUnused extends MiniPhase:
188187
val newCtx = if tree.symbol.exists then ctx.withOwner(tree.symbol) else ctx
189188
tree match
190189
case imp:tpd.Import =>
191-
_key.unusedDataApply(_.registerImport(imp))
190+
unusedDataApply(_.registerImport(imp))
192191
traverseChildren(tree)(using newCtx)
193192
case ident: Ident =>
194193
prepareForIdent(ident)
@@ -198,7 +197,7 @@ class CheckUnused extends MiniPhase:
198197
traverseChildren(tree)(using newCtx)
199198
case _: (tpd.Block | tpd.Template | tpd.PackageDef) =>
200199
//! DIFFERS FROM MINIPHASE
201-
_key.unusedDataApply { ud =>
200+
unusedDataApply { ud =>
202201
ud.inNewScope(ScopeType.fromTree(tree))(traverseChildren(tree)(using newCtx))
203202
}
204203
case t:tpd.ValDef =>
@@ -216,9 +215,10 @@ class CheckUnused extends MiniPhase:
216215
case t: tpd.Bind =>
217216
prepareForBind(t)
218217
traverseChildren(tree)(using newCtx)
218+
case _: tpd.InferredTypeTree =>
219219
case t@tpd.TypeTree() =>
220220
//! DIFFERS FROM MINIPHASE
221-
typeTraverser(_key.unusedDataApply).traverse(t.tpe)
221+
typeTraverser(unusedDataApply).traverse(t.tpe)
222222
traverseChildren(tree)(using newCtx)
223223
case _ =>
224224
//! DIFFERS FROM MINIPHASE
@@ -228,9 +228,14 @@ class CheckUnused extends MiniPhase:
228228

229229
/** This is a type traverser which catch some special Types not traversed by the term traverser above */
230230
private def typeTraverser(dt: (UnusedData => Any) => Unit)(using Context) = new TypeTraverser:
231-
override def traverse(tp: Type): Unit = tp match
232-
case AnnotatedType(_, annot) => dt(_.registerUsed(annot.symbol, None))
233-
case _ => traverseChildren(tp)
231+
override def traverse(tp: Type): Unit =
232+
if tp.typeSymbol.exists then dt(_.registerUsed(tp.typeSymbol, Some(tp.typeSymbol.name)))
233+
tp match
234+
case AnnotatedType(_, annot) =>
235+
dt(_.registerUsed(annot.symbol, None))
236+
traverseChildren(tp)
237+
case _ =>
238+
traverseChildren(tp)
234239

235240
/** Do the actual reporting given the result of the anaylsis */
236241
private def reportUnused(res: UnusedData.UnusedResult)(using Context): Unit =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// scalac: -Wunused:imports
2+
3+
trait Outer:
4+
trait Used
5+
trait Unused
6+
7+
object Test {
8+
val outer: Outer = ???
9+
import outer.{Used, Unused} // error
10+
def foo(x: Any): Used = x.asInstanceOf[Used]
11+
}
12+
13+
trait Outer1:
14+
trait UnusedToo1
15+
trait Unused1
16+
def unusedToo1: UnusedToo1
17+
18+
object Test1 {
19+
val outer1: Outer1 = ???
20+
import outer1.{Unused1, UnusedToo1} // error // error
21+
def foo() = outer1.unusedToo1 // in this case UnusedToo1 is not used explicitly, only inferred
22+
}

0 commit comments

Comments
 (0)