diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 53f991806641..6f7f77de70a5 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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) diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index 3825e04e9a16..0f0a1c29dea3 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -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 @@ -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 diff --git a/tests/warn/i17314.scala b/tests/warn/i17314.scala index cff90d843c38..3b5a486a6785 100644 --- a/tests/warn/i17314.scala +++ b/tests/warn/i17314.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:all -deprecation -feature +//> using options -Wunused:all -deprecation -feature -Werror import java.net.URI @@ -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 diff --git a/tests/warn/i23250.scala b/tests/warn/i23250.scala new file mode 100644 index 000000000000..ac9183ed1fd1 --- /dev/null +++ b/tests/warn/i23250.scala @@ -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] diff --git a/tests/warn/i23250b.scala b/tests/warn/i23250b.scala new file mode 100644 index 000000000000..f9e18559fb46 --- /dev/null +++ b/tests/warn/i23250b.scala @@ -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()