From 45b677848f6ba3dc848698d27a5689c35eeee486 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 8 Aug 2025 16:08:14 -0700 Subject: [PATCH] Drill through type lambda for tree symbol Select node in `new p.C[T]` has a lambda type, so the symbol `C` is found in its result type. The TypeApply has a symbol which is the constructor of C. Both trees are used to register `C` as used. [Cherry-picked 28a49218ec09605ce57cd832220dd5580c1003c8] --- .../tools/dotc/transform/CheckUnused.scala | 16 ++++++++--- tests/warn/i23694.scala | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 tests/warn/i23694.scala diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 465f6d46a86f..61c683202955 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -82,7 +82,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha && tree.qualifier.tpe.match case ThisType(_) | SuperType(_, _) => false case qualtpe => qualtpe.isStable - if tree.srcPos.isSynthetic && tree.symbol == defn.TypeTest_unapply then + val sym = tree.symbol + .orElse: + tree.typeOpt.resultType.typeSymbol + if tree.srcPos.isSynthetic && sym == defn.TypeTest_unapply then tree.qualifier.tpe.underlying.finalResultType match case AppliedType(tycon, args) => val res = @@ -92,11 +95,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha val target = res.dealias.typeSymbol resolveUsage(target, target.name, res.importPrefix.skipPackageObject) // case _: T => case _ => - else if isImportable || name.exists(_ != tree.symbol.name) then + else if isImportable || name.exists(_ != sym.name) then if !ignoreTree(tree) then - resolveUsage(tree.symbol, name, tree.qualifier.tpe) + resolveUsage(sym, name, tree.qualifier.tpe) else if !ignoreTree(tree) then - refUsage(tree.symbol) + refUsage(sym) refInfos.isAssignment = false tree @@ -126,6 +129,11 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha case _ => tree + override def transformTypeApply(tree: TypeApply)(using Context): tree.type = + if tree.symbol.exists && tree.symbol.isConstructor then + refUsage(tree.symbol.owner) // redundant with use of resultType in transformSelect of fun + tree + override def prepareForAssign(tree: Assign)(using Context): Context = tree.lhs.putAttachment(AssignmentTarget, ()) // don't take LHS reference as a read ctx diff --git a/tests/warn/i23694.scala b/tests/warn/i23694.scala new file mode 100644 index 000000000000..f29a6dbde7f2 --- /dev/null +++ b/tests/warn/i23694.scala @@ -0,0 +1,27 @@ +//> using options -Wunused:privates + +trait A: + def get: Any = new A.C // select has type [T] =>> C[T] + def cc: Any = new A.CC // select has type CC + +object A: + private class C[T] + private type CC[T] = C[T] + +trait B: + def get: Any = new B.C + +object B: + private class C + +// duplicate issue #23960 +package net.marek.tyre.automaton: + + private[tyre] class TyreCompiler[IN <: Tuple, R]: + private def compile[IS <: Tuple, T](xs: List[T]): String = xs match // warn + case _: List[t] => + Loop[IS, t](null.asInstanceOf[t]).build + private class Loop[IS <: Tuple, T]( + val i: T, + ): + def build = "27"