Skip to content

Commit c7570c8

Browse files
committed
Suppress "extension method will never be selected" for overrides
When we're overriding an existing extension method, we don't have the liberty of renaming the method, so we shouldn't get warnings we can't do anything about.
1 parent 0ee804f commit c7570c8

File tree

2 files changed

+40
-25
lines changed

2 files changed

+40
-25
lines changed

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

+28-25
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,8 @@ object RefChecks {
11081108
* An extension method is hidden if it does not offer a parameter that is not subsumed
11091109
* by the corresponding parameter of the member with the same name (or of all alternatives of an overload).
11101110
*
1111+
* This check is suppressed if this method is an override.
1112+
*
11111113
* For example, it is not possible to define a type-safe extension `contains` for `Set`,
11121114
* since for any parameter type, the existing `contains` method will compile and would be used.
11131115
*
@@ -1125,31 +1127,32 @@ object RefChecks {
11251127
* If the extension method is nullary, it is always hidden by a member of the same name.
11261128
* (Either the member is nullary, or the reference is taken as the eta-expansion of the member.)
11271129
*/
1128-
def checkExtensionMethods(sym: Symbol)(using Context): Unit = if sym.is(Extension) then
1129-
extension (tp: Type)
1130-
def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType
1131-
def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1132-
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
1133-
val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver
1134-
val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter
1135-
def hidden =
1136-
target.nonPrivateMember(sym.name)
1137-
.filterWithPredicate:
1138-
member =>
1139-
val memberIsImplicit = member.info.hasImplicitParams
1140-
val paramTps =
1141-
if memberIsImplicit then methTp.stripPoly.firstParamTypes
1142-
else methTp.firstExplicitParamTypes
1143-
1144-
paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || {
1145-
val memberParamTps = member.info.stripPoly.firstParamTypes
1146-
!memberParamTps.isEmpty
1147-
&& memberParamTps.lengthCompare(paramTps) == 0
1148-
&& memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m)
1149-
}
1150-
.exists
1151-
if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden
1152-
then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
1130+
def checkExtensionMethods(sym: Symbol)(using Context): Unit =
1131+
if sym.is(Extension) && !sym.nextOverriddenSymbol.exists then
1132+
extension (tp: Type)
1133+
def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType
1134+
def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1135+
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
1136+
val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver
1137+
val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter
1138+
def hidden =
1139+
target.nonPrivateMember(sym.name)
1140+
.filterWithPredicate:
1141+
member =>
1142+
val memberIsImplicit = member.info.hasImplicitParams
1143+
val paramTps =
1144+
if memberIsImplicit then methTp.stripPoly.firstParamTypes
1145+
else methTp.firstExplicitParamTypes
1146+
1147+
paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || {
1148+
val memberParamTps = member.info.stripPoly.firstParamTypes
1149+
!memberParamTps.isEmpty
1150+
&& memberParamTps.lengthCompare(paramTps) == 0
1151+
&& memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m)
1152+
}
1153+
.exists
1154+
if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden
1155+
then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
11531156
end checkExtensionMethods
11541157

11551158
/** Verify that references in the user-defined `@implicitNotFound` message are valid.

tests/pos/ext-override.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//> using options -Xfatal-warnings
2+
3+
trait Foo[T]:
4+
extension (x: T)
5+
def hi: String
6+
7+
class Bla:
8+
def hi: String = "hi"
9+
object Bla:
10+
given Foo[Bla] with
11+
extension (x: Bla)
12+
def hi: String = x.hi

0 commit comments

Comments
 (0)