Skip to content

Dealias for unused param check #23256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ object SymDenotations {
isAbstractOrAliasType && !isAbstractOrParamType

/** Is this symbol an abstract or alias type? */
final def isAbstractOrAliasType: Boolean = isType & !isClass
final def isAbstractOrAliasType: Boolean = isType && !isClass

/** Is this symbol an abstract type or type parameter? */
final def isAbstractOrParamType(using Context): Boolean = this.isOneOf(DeferredOrTypeParam)
Expand Down
17 changes: 12 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/CheckUnused.scala
Original file line number Diff line number Diff line change
Expand Up @@ -575,14 +575,14 @@ object CheckUnused:
|| m.hasAnnotation(dd.UnusedAnnot) // param of unused method
|| sym.name.is(ContextFunctionParamName) // a ubiquitous parameter
|| sym.isCanEqual
|| sym.info.typeSymbol.match // more ubiquity
|| sym.info.dealias.typeSymbol.match // more ubiquity
case dd.DummyImplicitClass | dd.SubTypeClass | dd.SameTypeClass => true
case tps =>
tps.isMarkerTrait // no members to use; was only if sym.name.is(ContextBoundParamName)
|| // but consider NotGiven
tps.hasAnnotation(dd.LanguageFeatureMetaAnnot)
|| sym.info.isSingleton // DSL friendly
|| sym.info.isInstanceOf[RefinedType] // can't be expressed as a context bound
|| sym.info.dealias.isInstanceOf[RefinedType] // can't be expressed as a context bound
if ctx.settings.WunusedHas.implicits
&& !infos.skip(m)
&& !m.isEffectivelyOverride
Expand Down Expand Up @@ -905,9 +905,16 @@ object CheckUnused:
def isCanEqual: Boolean =
sym.isOneOf(GivenOrImplicit) && sym.info.finalResultType.baseClasses.exists(_.derivesFrom(defn.CanEqualClass))
def isMarkerTrait: Boolean =
sym.isClass && sym.info.allMembers.forall: d =>
val m = d.symbol
!m.isTerm || m.isSelfSym || m.is(Method) && (m.owner == defn.AnyClass || m.owner == defn.ObjectClass)
def isEmptyInterface(info: Type): Boolean =
info.allMembers.forall: d =>
val m = d.symbol
!m.isTerm || m.isSelfSym || m.is(Method) && (m.owner == defn.AnyClass || m.owner == defn.ObjectClass)
if sym.isClass then isEmptyInterface(sym.info)
else if sym.is(Deferred) then
sym.info match
case TypeBounds(_, hi) => hi == defn.AnyType || isEmptyInterface(hi)
case _ => true
else false
def isEffectivelyPrivate: Boolean =
sym.is(Private, butNot = ParamAccessor)
|| sym.owner.isAnonymousClass && !sym.isEffectivelyOverride
Expand Down
4 changes: 2 additions & 2 deletions tests/warn/i17314.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//> using options -Wunused:all -deprecation -feature
//> using options -Wunused:all -deprecation -feature -Werror

import java.net.URI

Expand All @@ -10,7 +10,7 @@ object circelike {
type Configuration
trait ConfiguredCodec[T]
object ConfiguredCodec:
inline final def derived[A](using conf: Configuration)(using inline mirror: Mirror.Of[A]): ConfiguredCodec[A] = // warn // warn
inline final def derived[A](using conf: Configuration)(using inline mirror: Mirror.Of[A]): ConfiguredCodec[A] =
class InlinedConfiguredCodec extends ConfiguredCodec[A]:
val codec = summonInline[Codec[URI]] // simplification
new InlinedConfiguredCodec
Expand Down
17 changes: 17 additions & 0 deletions tests/warn/i23250.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//> using options -Wunused:all -Werror

trait MonadError[F[_], E]
type MonadThrow[F[_]] = MonadError[F, Throwable]

trait MetaStreams[F[_]]:
def use[A]: F[A] = ???
trait WriteResult

trait MetaStreamsSyntax:
extension [F[_]](ms: MetaStreams[F])(using MonadThrow[F])
def setMaxAge(): F[WriteResult] =
summon[MonadThrow[F]]
ms.use[WriteResult]

def setTruncateBefore(): F[WriteResult] =
ms.use[WriteResult]
18 changes: 18 additions & 0 deletions tests/warn/i23250b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//> using options -Wunused:all

trait Memberly:
def member: Int

object Members:
type MemberType <: Memberly
type Empty

object Test:
import Members.*

type MT = MemberType
def membered(using MT) = println() // warn abstract type offers member in upper bound
def remembered(using mt: MT) = mt.member

type Ignore = Empty
def emptily(using Ignore) = println()
Loading