Skip to content

Commit 8cbba06

Browse files
committed
Remove premature, brittle caching in lint
1 parent 57807c6 commit 8cbba06

File tree

2 files changed

+35
-72
lines changed

2 files changed

+35
-72
lines changed

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

+1-72
Original file line numberDiff line numberDiff line change
@@ -215,15 +215,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
215215
refInfos.register(tree)
216216
tree
217217

218-
override def prepareForTemplate(tree: Template)(using Context): Context =
219-
ctx.fresh.setProperty(resolvedKey, Resolved())
220-
221-
override def prepareForPackageDef(tree: PackageDef)(using Context): Context =
222-
ctx.fresh.setProperty(resolvedKey, Resolved())
223-
224-
override def prepareForStats(trees: List[Tree])(using Context): Context =
225-
ctx.fresh.setProperty(resolvedKey, Resolved())
226-
227218
override def transformOther(tree: Tree)(using Context): tree.type =
228219
tree match
229220
case imp: Import =>
@@ -289,7 +280,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
289280
case ByNameTypeTree(result) =>
290281
transformAllDeep(result)
291282
//case _: InferredTypeTree => // do nothing
292-
//case _: Export => // nothing to do
293283
//case _ if tree.isType =>
294284
case _ =>
295285
tree
@@ -350,15 +340,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
350340
&& ctxsym.thisType.baseClasses.contains(sym.owner)
351341
&& ctxsym.thisType.member(sym.name).hasAltWith(d => d.containsSym(sym) && !name.exists(_ != d.name))
352342

353-
// Attempt to cache a result at the given context. Not all contexts bear a cache, including NoContext.
354-
// If there is already any result for the name and prefix, do nothing.
355-
def addCached(where: Context, result: Precedence): Unit =
356-
if where.moreProperties ne null then
357-
where.property(resolvedKey) match
358-
case Some(resolved) =>
359-
resolved.record(sym, name, prefix, result)
360-
case none =>
361-
362343
// Avoid spurious NoSymbol and also primary ctors which are never warned about.
363344
// Selections C.this.toString should be already excluded, but backtopped here for eq, etc.
364345
if !sym.exists || sym.isPrimaryConstructor || sym.isEffectiveRoot || defn.topClasses(sym.owner) then return
@@ -367,39 +348,19 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
367348
// If the sym is an enclosing definition (the owner of a context), it does not count toward usages.
368349
val isLocal = sym.isLocalToBlock
369350
var candidate: Context = NoContext
370-
var cachePoint: Context = NoContext // last context with Resolved cache
371351
var importer: ImportSelector | Null = null // non-null for import context
372352
var precedence = NoPrecedence // of current resolution
373353
var done = false
374-
var cached = false
375354
val ctxs = ctx.outersIterator
376355
while !done && ctxs.hasNext do
377356
val cur = ctxs.next()
378357
if cur.owner eq sym then
379-
addCached(cachePoint, Definition)
380358
return // found enclosing definition
381359
else if isLocal then
382360
if cur.owner eq sym.owner then
383361
done = true // for local def, just checking that it is not enclosing
384362
else
385-
val cachedPrecedence =
386-
cur.property(resolvedKey) match
387-
case Some(resolved) =>
388-
// conservative, cache must be nested below the result context
389-
if precedence.isNone then
390-
cachePoint = cur // no result yet, and future result could be cached here
391-
resolved.hasRecord(sym, name, prefix)
392-
case none => NoPrecedence
393-
cached = !cachedPrecedence.isNone
394-
if cached then
395-
// if prefer cached precedence, then discard previous result
396-
if precedence.weakerThan(cachedPrecedence) then
397-
candidate = NoContext
398-
importer = null
399-
cachePoint = cur // actual cache context
400-
precedence = cachedPrecedence // actual cached precedence
401-
done = true
402-
else if cur.isImportContext then
363+
if cur.isImportContext then
403364
val sel = matchingSelector(cur.importInfo.nn)
404365
if sel != null then
405366
if cur.importInfo.nn.isRootImport then
@@ -432,13 +393,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
432393
refInfos.refs.addOne(sym)
433394
if candidate != NoContext && candidate.isImportContext && importer != null then
434395
refInfos.sels.put(importer, ())
435-
// possibly record that we have performed this look-up
436-
// if no result was found, take it as Definition (local or rooted head of fully qualified path)
437-
val adjusted = if precedence.isNone then Definition else precedence
438-
if !cached && (cachePoint ne NoContext) then
439-
addCached(cachePoint, adjusted)
440-
if cachePoint ne ctx then
441-
addCached(ctx, adjusted) // at this ctx, since cachePoint may be far up the outer chain
442396
end resolveUsage
443397
end CheckUnused
444398

@@ -450,15 +404,8 @@ object CheckUnused:
450404

451405
val refInfosKey = Property.StickyKey[RefInfos]
452406

453-
val resolvedKey = Property.Key[Resolved]
454-
455407
inline def refInfos(using Context): RefInfos = ctx.property(refInfosKey).get
456408

457-
inline def resolved(using Context): Resolved =
458-
ctx.property(resolvedKey) match
459-
case Some(res) => res
460-
case _ => throw new MatchError("no Resolved for context")
461-
462409
/** Attachment holding the name of an Ident as written by the user. */
463410
val OriginalName = Property.StickyKey[Name]
464411

@@ -514,24 +461,6 @@ object CheckUnused:
514461
var inliners = 0 // depth of inline def (not inlined yet)
515462
end RefInfos
516463

517-
// Symbols already resolved in the given Context (with name and prefix of lookup).
518-
class Resolved:
519-
import PrecedenceLevels.*
520-
private val seen = mutable.Map.empty[Symbol, List[(Name, Type, Precedence)]].withDefaultValue(Nil)
521-
// if a result has been recorded, return it; otherwise, NoPrecedence.
522-
def hasRecord(symbol: Symbol, name: Name, prefix: Type)(using Context): Precedence =
523-
seen(symbol).find((n, p, _) => n == name && p =:= prefix) match
524-
case Some((_, _, r)) => r
525-
case none => NoPrecedence
526-
// "record" the look-up result, if there is not already a result for the name and prefix.
527-
def record(symbol: Symbol, name: Name, prefix: Type, result: Precedence)(using Context): Unit =
528-
require(NoPrecedence.weakerThan(result))
529-
seen.updateWith(symbol):
530-
case svs @ Some(vs) =>
531-
if vs.exists((n, p, _) => n == name && p =:= prefix) then svs
532-
else Some((name, prefix, result) :: vs)
533-
case none => Some((name, prefix, result) :: Nil)
534-
535464
// Names are resolved by definitions and imports, which have four precedence levels:
536465
object PrecedenceLevels:
537466
opaque type Precedence = Int

tests/warn/i22971.scala

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//> using options -Wunused:imports
2+
3+
package p:
4+
5+
trait Base
6+
class Class extends Base
7+
8+
abstract class Entity[T: GetType]
9+
10+
class Thing extends Entity[Class]
11+
12+
trait GetType[T]
13+
14+
object GetType {
15+
//implicit object GetTypeClass extends GetType[Class]
16+
implicit val GetTypeClass: GetType[Class] = new GetType[Class] {}
17+
}
18+
object Main {
19+
def main(args: Array[String]): Unit = {
20+
import GetType.*
21+
val e = GetTypeClass
22+
}
23+
}
24+
25+
package q:
26+
27+
class C:
28+
def f =
29+
import p.*
30+
GetType.GetTypeClass
31+
def g =
32+
import p.GetType.*
33+
GetTypeClass
34+
class D extends p.Entity[p.Class]

0 commit comments

Comments
 (0)