Skip to content

Commit 10ed3bd

Browse files
Backport "Fix #20146: attach the original name if there is an import selection for an indent" to LTS (#21095)
Backports #20163 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 591477b + aa18455 commit 10ed3bd

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

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

+26-20
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _ke
9797
ctx
9898

9999
override def prepareForSelect(tree: tpd.Select)(using Context): Context =
100-
unusedDataApply(_.registerUsed(tree.symbol, Some(tree.name)))
100+
val name = tree.removeAttachment(OriginalName).orElse(Some(tree.name))
101+
unusedDataApply(_.registerUsed(tree.symbol, name))
101102

102103
override def prepareForBlock(tree: tpd.Block)(using Context): Context =
103104
pushInBlockTemplatePackageDef(tree)
@@ -328,6 +329,8 @@ object CheckUnused:
328329
*/
329330
private val _key = Property.StickyKey[UnusedData]
330331

332+
val OriginalName = Property.StickyKey[Name]
333+
331334
class PostTyper extends CheckUnused(PhaseMode.Aggregate, "PostTyper", _key)
332335

333336
class PostInlining extends CheckUnused(PhaseMode.Report, "PostInlining", _key)
@@ -680,36 +683,39 @@ object CheckUnused:
680683
}
681684

682685
/** Given an import and accessibility, return selector that matches import<->symbol */
683-
private def isInImport(imp: tpd.Import, isAccessible: Boolean, symName: Option[Name], isDerived: Boolean)(using Context): Option[ImportSelector] =
686+
private def isInImport(imp: tpd.Import, isAccessible: Boolean, altName: Option[Name], isDerived: Boolean)(using Context): Option[ImportSelector] =
684687
val tpd.Import(qual, sels) = imp
685-
val dealiasedSym = dealias(sym)
686-
val simpleSelections = qual.tpe.member(sym.name).alternatives
687-
val typeSelections = sels.flatMap(n => qual.tpe.member(n.name.toTypeName).alternatives)
688-
val termSelections = sels.flatMap(n => qual.tpe.member(n.name.toTermName).alternatives)
689-
val sameTermPath = qual.isTerm && sym.exists && sym.owner.isType && qual.tpe.typeSymbol == sym.owner.asType
690-
val selectionsToDealias = typeSelections ::: termSelections
691-
val renamedSelection = if sameTermPath then sels.find(sel => sel.imported.name == sym.name) else None
692-
val qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(dealias).contains(dealiasedSym) || renamedSelection.isDefined
693-
def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && symName.map(n => n.toTermName == sel.rename).getOrElse(true))
694-
def dealiasedSelector = if(isDerived) sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
695-
case (sel, sym) if dealias(sym) == dealiasedSym => sel
696-
}.headOption else None
688+
val qualTpe = qual.tpe
689+
val dealiasedSym = sym.dealias
690+
val simpleSelections = qualTpe.member(sym.name).alternatives
691+
val selectionsToDealias = sels.flatMap(sel =>
692+
qualTpe.member(sel.name.toTypeName).alternatives
693+
::: qualTpe.member(sel.name.toTermName).alternatives)
694+
def qualHasSymbol = simpleSelections.map(_.symbol).contains(sym) || (simpleSelections ::: selectionsToDealias).map(_.symbol).map(_.dealias).contains(dealiasedSym)
695+
def selector = sels.find(sel => (sel.name.toTermName == sym.name || sel.name.toTypeName == sym.name) && altName.map(n => n.toTermName == sel.rename).getOrElse(true))
696+
def dealiasedSelector =
697+
if isDerived then
698+
sels.flatMap(sel => selectionsToDealias.map(m => (sel, m.symbol))).collect {
699+
case (sel, sym) if sym.dealias == dealiasedSym => sel
700+
}.headOption
701+
else None
697702
def givenSelector = if sym.is(Given) || sym.is(Implicit)
698703
then sels.filter(sel => sel.isGiven && !sel.bound.isEmpty).find(sel => sel.boundTpe =:= sym.info)
699704
else None
700705
def wildcard = sels.find(sel => sel.isWildcard && ((sym.is(Given) == sel.isGiven && sel.bound.isEmpty) || sym.is(Implicit)))
701-
if qualHasSymbol && (!isAccessible || sym.isRenamedSymbol(symName)) && sym.exists then
702-
selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard).orElse(renamedSelection) // selector with name or wildcard (or given)
706+
if sym.exists && qualHasSymbol && (!isAccessible || sym.isRenamedSymbol(altName)) then
707+
selector.orElse(dealiasedSelector).orElse(givenSelector).orElse(wildcard) // selector with name or wildcard (or given)
703708
else
704709
None
705710

706711
private def isRenamedSymbol(symNameInScope: Option[Name])(using Context) =
707712
sym.name != nme.NO_NAME && symNameInScope.exists(_.toSimpleName != sym.name.toSimpleName)
708713

709-
private def dealias(symbol: Symbol)(using Context): Symbol =
710-
if(symbol.isType && symbol.asType.denot.isAliasType) then
711-
symbol.asType.typeRef.dealias.typeSymbol
712-
else symbol
714+
private def dealias(using Context): Symbol =
715+
if sym.isType && sym.asType.denot.isAliasType then
716+
sym.asType.typeRef.dealias.typeSymbol
717+
else sym
718+
713719
/** Annotated with @unused */
714720
private def isUnusedAnnot(using Context): Boolean =
715721
sym.annotations.exists(a => a.symbol == ctx.definitions.UnusedAnnot)

compiler/src/dotty/tools/dotc/typer/Typer.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import Nullables.*
5050
import NullOpsDecorator.*
5151
import cc.CheckCaptures
5252
import config.Config
53+
import transform.CheckUnused.OriginalName
5354

5455
import scala.annotation.constructorOnly
5556
import dotty.tools.dotc.rewrites.Rewrites
@@ -646,7 +647,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
646647
val selection = untpd.cpy.Select(tree)(qualifier, name)
647648
typed(selection, pt)
648649
else if rawType.exists then
649-
setType(ensureAccessible(rawType, superAccess = false, tree.srcPos))
650+
val ref = setType(ensureAccessible(rawType, superAccess = false, tree.srcPos))
651+
if ref.symbol.name != name then
652+
ref.withAttachment(OriginalName, name)
653+
else ref
650654
else if name == nme._scope then
651655
// gross hack to support current xml literals.
652656
// awaiting a better implicits based solution for library-supported xml

tests/warn/i20146.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//> using options -Wunused:imports
2+
3+
def test(list: List[Int]): Int =
4+
import list.{head => first}
5+
import list.{length => len} // warn
6+
import list.{addString => add} // warn
7+
first + list.length

0 commit comments

Comments
 (0)