|
1 | | -package dotty.tools.dotc.transform |
2 | | - |
3 | | -import dotty.tools.dotc.ast.desugar.{ForArtifact, PatternVar} |
4 | | -import dotty.tools.dotc.ast.tpd.* |
5 | | -import dotty.tools.dotc.ast.untpd, untpd.ImportSelector |
6 | | -import dotty.tools.dotc.config.ScalaSettings |
7 | | -import dotty.tools.dotc.core.Contexts.* |
8 | | -import dotty.tools.dotc.core.Flags.* |
9 | | -import dotty.tools.dotc.core.Names.{Name, SimpleName, DerivedName, TermName, termName} |
10 | | -import dotty.tools.dotc.core.NameOps.{isAnonymousFunctionName, isReplWrapperName, setterName} |
11 | | -import dotty.tools.dotc.core.NameKinds.{ |
12 | | - BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName} |
13 | | -import dotty.tools.dotc.core.StdNames.nme |
14 | | -import dotty.tools.dotc.core.Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} |
15 | | -import dotty.tools.dotc.core.Types.* |
16 | | -import dotty.tools.dotc.report |
17 | | -import dotty.tools.dotc.reporting.{CodeAction, UnusedSymbol} |
18 | | -import dotty.tools.dotc.rewrites.Rewrites |
19 | | -import dotty.tools.dotc.transform.MegaPhase.MiniPhase |
20 | | -import dotty.tools.dotc.typer.{ImportInfo, Typer} |
21 | | -import dotty.tools.dotc.typer.Deriving.OriginalTypeClass |
22 | | -import dotty.tools.dotc.util.{Property, Spans, SrcPos}, Spans.Span |
23 | | -import dotty.tools.dotc.util.Chars.{isLineBreakChar, isWhitespace} |
24 | | -import dotty.tools.dotc.util.chaining.* |
| 1 | +package dotty.tools.dotc |
| 2 | +package transform |
| 3 | + |
| 4 | +import ast.*, desugar.{ForArtifact, PatternVar}, tpd.*, untpd.ImportSelector |
| 5 | +import config.ScalaSettings |
| 6 | +import core.*, Contexts.*, Flags.* |
| 7 | +import Names.{Name, SimpleName, DerivedName, TermName, termName} |
| 8 | +import NameKinds.{BodyRetainerName, ContextBoundParamName, ContextFunctionParamName, DefaultGetterName, WildcardParamName} |
| 9 | +import NameOps.{isAnonymousFunctionName, isReplWrapperName, setterName} |
| 10 | +import Scopes.newScope |
| 11 | +import StdNames.nme |
| 12 | +import Symbols.{ClassSymbol, NoSymbol, Symbol, defn, isDeprecated, requiredClass, requiredModule} |
| 13 | +import Types.* |
| 14 | +import reporting.{CodeAction, UnusedSymbol} |
| 15 | +import rewrites.Rewrites |
| 16 | + |
| 17 | +import MegaPhase.MiniPhase |
| 18 | +import typer.{ImportInfo, Typer} |
| 19 | +import typer.Deriving.OriginalTypeClass |
| 20 | +import typer.Implicits.{ContextualImplicits, RenamedImplicitRef} |
| 21 | +import util.{Property, Spans, SrcPos}, Spans.Span |
| 22 | +import util.Chars.{isLineBreakChar, isWhitespace} |
| 23 | +import util.chaining.* |
25 | 24 |
|
26 | 25 | import java.util.IdentityHashMap |
27 | 26 |
|
@@ -56,17 +55,16 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
56 | 55 | if tree.symbol.exists then |
57 | 56 | // if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site |
58 | 57 | val resolving = |
59 | | - refInfos.inlined.isEmpty |
60 | | - || tree.srcPos.isZeroExtentSynthetic |
61 | | - || refInfos.inlined.exists(_.sourcePos.contains(tree.srcPos.sourcePos)) |
62 | | - if resolving && !ignoreTree(tree) then |
| 58 | + tree.srcPos.isUserCode |
| 59 | + || tree.srcPos.isZeroExtentSynthetic // take as summonInline |
| 60 | + if !ignoreTree(tree) then |
63 | 61 | def loopOverPrefixes(prefix: Type, depth: Int): Unit = |
64 | 62 | if depth < 10 && prefix.exists && !prefix.classSymbol.isEffectiveRoot then |
65 | | - resolveUsage(prefix.classSymbol, nme.NO_NAME, NoPrefix) |
| 63 | + resolveUsage(prefix.classSymbol, nme.NO_NAME, NoPrefix, imports = resolving) |
66 | 64 | loopOverPrefixes(prefix.normalizedPrefix, depth + 1) |
67 | 65 | if tree.srcPos.isZeroExtentSynthetic then |
68 | 66 | loopOverPrefixes(tree.typeOpt.normalizedPrefix, depth = 0) |
69 | | - resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject) |
| 67 | + resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject, imports = resolving) |
70 | 68 | else if tree.hasType then |
71 | 69 | resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject) |
72 | 70 | refInfos.isAssignment = false |
@@ -142,14 +140,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
142 | 140 | case _ => |
143 | 141 | tree |
144 | 142 |
|
145 | | - override def prepareForInlined(tree: Inlined)(using Context): Context = |
146 | | - refInfos.inlined.push(tree.call.srcPos) |
147 | | - ctx |
148 | 143 | override def transformInlined(tree: Inlined)(using Context): tree.type = |
149 | | - //transformAllDeep(tree.expansion) // traverse expansion with nonempty inlined stack to avoid registering defs |
150 | | - val _ = refInfos.inlined.pop() |
151 | | - if !tree.call.isEmpty && phaseMode.eq(PhaseMode.Aggregate) then |
152 | | - transformAllDeep(tree.call) |
| 144 | + transformAllDeep(tree.call) |
153 | 145 | tree |
154 | 146 |
|
155 | 147 | override def prepareForBind(tree: Bind)(using Context): Context = |
@@ -297,8 +289,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
297 | 289 | * e.g., in `scala.Int`, `scala` is in scope for typer, but here we reverse-engineer the attribution. |
298 | 290 | * For Select, lint does not look up `<empty>.scala` (so top-level syms look like magic) but records `scala.Int`. |
299 | 291 | * For Ident, look-up finds the root import as usual. A competing import is OK because higher precedence. |
| 292 | + * |
| 293 | + * The `imports` flag is whether an identifier can mark an import as used: the flag is false |
| 294 | + * for inlined code, except for `summonInline` (and related constructs) which are resolved at inlining. |
300 | 295 | */ |
301 | | - def resolveUsage(sym0: Symbol, name: Name, prefix: Type)(using Context): Unit = |
| 296 | + def resolveUsage(sym0: Symbol, name: Name, prefix: Type, imports: Boolean = true)(using Context): Unit = |
302 | 297 | import PrecedenceLevels.* |
303 | 298 | val sym = sym0.userSymbol |
304 | 299 |
|
@@ -392,7 +387,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
392 | 387 | // record usage and possibly an import |
393 | 388 | if !enclosed then |
394 | 389 | refInfos.addRef(sym) |
395 | | - if candidate != NoContext && candidate.isImportContext && importer != null then |
| 390 | + if imports && candidate != NoContext && candidate.isImportContext && importer != null then |
396 | 391 | refInfos.sels.put(importer, ()) |
397 | 392 | end resolveUsage |
398 | 393 | end CheckUnused |
@@ -432,7 +427,7 @@ object CheckUnused: |
432 | 427 | val nowarn = mutable.Set.empty[Symbol] // marked @nowarn |
433 | 428 | val imps = new IdentityHashMap[Import, Unit] // imports |
434 | 429 | val sels = new IdentityHashMap[ImportSelector, Unit] // matched selectors |
435 | | - def register(tree: Tree)(using Context): Unit = if inlined.isEmpty then |
| 430 | + def register(tree: Tree)(using Context): Unit = if tree.srcPos.isUserCode then |
436 | 431 | tree match |
437 | 432 | case imp: Import => |
438 | 433 | if inliners == 0 |
@@ -461,7 +456,6 @@ object CheckUnused: |
461 | 456 | if tree.symbol ne NoSymbol then |
462 | 457 | defs.addOne((tree.symbol, tree.srcPos)) // TODO is this a code path |
463 | 458 |
|
464 | | - val inlined = Stack.empty[SrcPos] // enclosing call.srcPos of inlined code (expansions) |
465 | 459 | var inliners = 0 // depth of inline def (not inlined yet) |
466 | 460 |
|
467 | 461 | // instead of refs.addOne, use addRef to distinguish a read from a write to var |
@@ -999,6 +993,10 @@ object CheckUnused: |
999 | 993 | extension (pos: SrcPos) |
1000 | 994 | def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.isZeroExtent |
1001 | 995 | def isSynthetic: Boolean = pos.span.isSynthetic && pos.span.exists |
| 996 | + def isUserCode(using Context): Boolean = |
| 997 | + val inlineds = enclosingInlineds // per current context |
| 998 | + inlineds.isEmpty |
| 999 | + || inlineds.last.srcPos.sourcePos.contains(pos.sourcePos) |
1002 | 1000 |
|
1003 | 1001 | extension [A <: AnyRef](arr: Array[A]) |
1004 | 1002 | // returns `until` if not satisfied |
|
0 commit comments