|
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.* |
| 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.* |
24 | 25 |
|
25 | 26 | import java.util.IdentityHashMap |
26 | 27 |
|
@@ -55,16 +56,17 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
55 | 56 | if tree.symbol.exists then |
56 | 57 | // if in an inline expansion, resolve at summonInline (synthetic pos) or in an enclosing call site |
57 | 58 | val resolving = |
58 | | - tree.srcPos.isUserCode |
59 | | - || tree.srcPos.isZeroExtentSynthetic // take as summonInline |
60 | | - if !ignoreTree(tree) then |
| 59 | + refInfos.inlined.isEmpty |
| 60 | + || tree.srcPos.isZeroExtentSynthetic |
| 61 | + || refInfos.inlined.exists(_.sourcePos.contains(tree.srcPos.sourcePos)) |
| 62 | + if resolving && !ignoreTree(tree) then |
61 | 63 | def loopOverPrefixes(prefix: Type, depth: Int): Unit = |
62 | 64 | if depth < 10 && prefix.exists && !prefix.classSymbol.isEffectiveRoot then |
63 | | - resolveUsage(prefix.classSymbol, nme.NO_NAME, NoPrefix, imports = resolving) |
| 65 | + resolveUsage(prefix.classSymbol, nme.NO_NAME, NoPrefix) |
64 | 66 | loopOverPrefixes(prefix.normalizedPrefix, depth + 1) |
65 | 67 | if tree.srcPos.isZeroExtentSynthetic then |
66 | 68 | loopOverPrefixes(tree.typeOpt.normalizedPrefix, depth = 0) |
67 | | - resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject, imports = resolving) |
| 69 | + resolveUsage(tree.symbol, tree.name, tree.typeOpt.importPrefix.skipPackageObject) |
68 | 70 | else if tree.hasType then |
69 | 71 | resolveUsage(tree.tpe.classSymbol, tree.name, tree.tpe.importPrefix.skipPackageObject) |
70 | 72 | refInfos.isAssignment = false |
@@ -140,8 +142,14 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
140 | 142 | case _ => |
141 | 143 | tree |
142 | 144 |
|
| 145 | + override def prepareForInlined(tree: Inlined)(using Context): Context = |
| 146 | + refInfos.inlined.push(tree.call.srcPos) |
| 147 | + ctx |
143 | 148 | override def transformInlined(tree: Inlined)(using Context): tree.type = |
144 | | - transformAllDeep(tree.call) |
| 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) |
145 | 153 | tree |
146 | 154 |
|
147 | 155 | override def prepareForBind(tree: Bind)(using Context): Context = |
@@ -289,11 +297,8 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
289 | 297 | * e.g., in `scala.Int`, `scala` is in scope for typer, but here we reverse-engineer the attribution. |
290 | 298 | * For Select, lint does not look up `<empty>.scala` (so top-level syms look like magic) but records `scala.Int`. |
291 | 299 | * 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. |
295 | 300 | */ |
296 | | - def resolveUsage(sym0: Symbol, name: Name, prefix: Type, imports: Boolean = true)(using Context): Unit = |
| 301 | + def resolveUsage(sym0: Symbol, name: Name, prefix: Type)(using Context): Unit = |
297 | 302 | import PrecedenceLevels.* |
298 | 303 | val sym = sym0.userSymbol |
299 | 304 |
|
@@ -387,7 +392,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha |
387 | 392 | // record usage and possibly an import |
388 | 393 | if !enclosed then |
389 | 394 | refInfos.addRef(sym) |
390 | | - if imports && candidate != NoContext && candidate.isImportContext && importer != null then |
| 395 | + if candidate != NoContext && candidate.isImportContext && importer != null then |
391 | 396 | refInfos.sels.put(importer, ()) |
392 | 397 | end resolveUsage |
393 | 398 | end CheckUnused |
@@ -427,7 +432,7 @@ object CheckUnused: |
427 | 432 | val nowarn = mutable.Set.empty[Symbol] // marked @nowarn |
428 | 433 | val imps = new IdentityHashMap[Import, Unit] // imports |
429 | 434 | val sels = new IdentityHashMap[ImportSelector, Unit] // matched selectors |
430 | | - def register(tree: Tree)(using Context): Unit = if tree.srcPos.isUserCode then |
| 435 | + def register(tree: Tree)(using Context): Unit = if inlined.isEmpty then |
431 | 436 | tree match |
432 | 437 | case imp: Import => |
433 | 438 | if inliners == 0 |
@@ -457,6 +462,7 @@ object CheckUnused: |
457 | 462 | if tree.symbol ne NoSymbol then |
458 | 463 | defs.addOne((tree.symbol, tree.srcPos)) // TODO is this a code path |
459 | 464 |
|
| 465 | + val inlined = Stack.empty[SrcPos] // enclosing call.srcPos of inlined code (expansions) |
460 | 466 | var inliners = 0 // depth of inline def (not inlined yet) |
461 | 467 |
|
462 | 468 | // instead of refs.addOne, use addRef to distinguish a read from a write to var |
@@ -998,10 +1004,6 @@ object CheckUnused: |
998 | 1004 | extension (pos: SrcPos) |
999 | 1005 | def isZeroExtentSynthetic: Boolean = pos.span.isSynthetic && pos.span.isZeroExtent |
1000 | 1006 | def isSynthetic: Boolean = pos.span.isSynthetic && pos.span.exists |
1001 | | - def isUserCode(using Context): Boolean = |
1002 | | - val inlineds = enclosingInlineds // per current context |
1003 | | - inlineds.isEmpty |
1004 | | - || inlineds.last.srcPos.sourcePos.contains(pos.sourcePos) |
1005 | 1007 |
|
1006 | 1008 | extension [A <: AnyRef](arr: Array[A]) |
1007 | 1009 | // returns `until` if not satisfied |
|
0 commit comments