Skip to content

Commit 844cb87

Browse files
som-snytttgodzik
authored andcommitted
Remove premature, brittle caching in lint
1 parent 068bf4e commit 844cb87

File tree

2 files changed

+35
-71
lines changed

2 files changed

+35
-71
lines changed

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

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
195195
refInfos.register(tree)
196196
tree
197197

198-
override def prepareForTemplate(tree: Template)(using Context): Context =
199-
ctx.fresh.setProperty(resolvedKey, Resolved())
200-
201-
override def prepareForPackageDef(tree: PackageDef)(using Context): Context =
202-
ctx.fresh.setProperty(resolvedKey, Resolved())
203-
204-
override def prepareForStats(trees: List[Tree])(using Context): Context =
205-
ctx.fresh.setProperty(resolvedKey, Resolved())
206-
207198
override def transformOther(tree: Tree)(using Context): tree.type =
208199
tree match
209200
case imp: Import =>
@@ -254,7 +245,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
254245
case ByNameTypeTree(result) =>
255246
transformAllDeep(result)
256247
//case _: InferredTypeTree => // do nothing
257-
//case _: Export => // nothing to do
258248
//case _ if tree.isType =>
259249
case _ =>
260250
tree
@@ -317,15 +307,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
317307
&& ctxsym.thisType.baseClasses.contains(sym.owner)
318308
&& ctxsym.thisType.member(sym.name).hasAltWith(d => d.containsSym(sym) && !name.exists(_ != d.name))
319309

320-
// Attempt to cache a result at the given context. Not all contexts bear a cache, including NoContext.
321-
// If there is already any result for the name and prefix, do nothing.
322-
def addCached(where: Context, result: Precedence): Unit =
323-
if where.moreProperties ne null then
324-
where.property(resolvedKey) match
325-
case Some(resolved) =>
326-
resolved.record(sym, name, prefix, result)
327-
case none =>
328-
329310
// Avoid spurious NoSymbol and also primary ctors which are never warned about.
330311
// Selections C.this.toString should be already excluded, but backstopped here for eq, etc.
331312
if !sym.exists || sym.isPrimaryConstructor || sym.isEffectiveRoot || defn.topClasses(sym.owner) then return
@@ -334,12 +315,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
334315
// If the sym is an enclosing definition (the owner of a context), it does not count toward usages.
335316
val isLocal = sym.isLocalToBlock
336317
var candidate: Context = NoContext
337-
var cachePoint: Context = NoContext // last context with Resolved cache
338318
var importer: ImportSelector | Null = null // non-null for import context
339319
var precedence = NoPrecedence // of current resolution
340320
var enclosed = false // true if sym is owner of an enclosing context
341321
var done = false
342-
var cached = false
343322
val ctxs = ctx.outersIterator
344323
while !done && ctxs.hasNext do
345324
val cur = ctxs.next()
@@ -349,24 +328,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
349328
if cur.owner eq sym.owner then
350329
done = true // for local def, just checking that it is not enclosing
351330
else
352-
val cachedPrecedence =
353-
cur.property(resolvedKey) match
354-
case Some(resolved) =>
355-
// conservative, cache must be nested below the result context
356-
if precedence.isNone then
357-
cachePoint = cur // no result yet, and future result could be cached here
358-
resolved.hasRecord(sym, name, prefix)
359-
case none => NoPrecedence
360-
cached = !cachedPrecedence.isNone
361-
if cached then
362-
// if prefer cached precedence, then discard previous result
363-
if precedence.weakerThan(cachedPrecedence) then
364-
candidate = NoContext
365-
importer = null
366-
cachePoint = cur // actual cache context
367-
precedence = cachedPrecedence // actual cached precedence
368-
done = true
369-
else if cur.isImportContext then
331+
if cur.isImportContext then
370332
val sel = matchingSelector(cur.importInfo.nn)
371333
if sel != null then
372334
if cur.importInfo.nn.isRootImport then
@@ -400,13 +362,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha
400362
refInfos.addRef(sym)
401363
if candidate != NoContext && candidate.isImportContext && importer != null then
402364
refInfos.sels.put(importer, ())
403-
// possibly record that we have performed this look-up
404-
// if no result was found, take it as Definition (local or rooted head of fully qualified path)
405-
val adjusted = if precedence.isNone then Definition else precedence
406-
if !cached && (cachePoint ne NoContext) then
407-
addCached(cachePoint, adjusted)
408-
if cachePoint ne ctx then
409-
addCached(ctx, adjusted) // at this ctx, since cachePoint may be far up the outer chain
410365
end resolveUsage
411366
end CheckUnused
412367

@@ -418,15 +373,8 @@ object CheckUnused:
418373

419374
val refInfosKey = Property.StickyKey[RefInfos]
420375

421-
val resolvedKey = Property.Key[Resolved]
422-
423376
inline def refInfos(using Context): RefInfos = ctx.property(refInfosKey).get
424377

425-
inline def resolved(using Context): Resolved =
426-
ctx.property(resolvedKey) match
427-
case Some(res) => res
428-
case _ => throw new MatchError("no Resolved for context")
429-
430378
/** Attachment holding the name of an Ident as written by the user. */
431379
val OriginalName = Property.StickyKey[Name]
432380

@@ -493,24 +441,6 @@ object CheckUnused:
493441
refs.addOne(sym)
494442
end RefInfos
495443

496-
// Symbols already resolved in the given Context (with name and prefix of lookup).
497-
class Resolved:
498-
import PrecedenceLevels.*
499-
private val seen = mutable.Map.empty[Symbol, List[(Name, Type, Precedence)]].withDefaultValue(Nil)
500-
// if a result has been recorded, return it; otherwise, NoPrecedence.
501-
def hasRecord(symbol: Symbol, name: Name, prefix: Type)(using Context): Precedence =
502-
seen(symbol).find((n, p, _) => n == name && p =:= prefix) match
503-
case Some((_, _, r)) => r
504-
case none => NoPrecedence
505-
// "record" the look-up result, if there is not already a result for the name and prefix.
506-
def record(symbol: Symbol, name: Name, prefix: Type, result: Precedence)(using Context): Unit =
507-
require(NoPrecedence.weakerThan(result))
508-
seen.updateWith(symbol):
509-
case svs @ Some(vs) =>
510-
if vs.exists((n, p, _) => n == name && p =:= prefix) then svs
511-
else Some((name, prefix, result) :: vs)
512-
case none => Some((name, prefix, result) :: Nil)
513-
514444
// Names are resolved by definitions and imports, which have four precedence levels:
515445
object PrecedenceLevels:
516446
opaque type Precedence = Int

tests/warn/i22971.scala

Lines changed: 34 additions & 0 deletions
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)