Skip to content

Commit cb761cb

Browse files
smarterWojciechMazur
authored andcommitted
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. [Cherry-picked c7570c8]
1 parent 9292a2d commit cb761cb

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
@@ -1026,6 +1026,8 @@ object RefChecks {
10261026
* An extension method is hidden if it does not offer a parameter that is not subsumed
10271027
* by the corresponding parameter of the member with the same name (or of all alternatives of an overload).
10281028
*
1029+
* This check is suppressed if this method is an override.
1030+
*
10291031
* For example, it is not possible to define a type-safe extension `contains` for `Set`,
10301032
* since for any parameter type, the existing `contains` method will compile and would be used.
10311033
*
@@ -1043,31 +1045,32 @@ object RefChecks {
10431045
* If the extension method is nullary, it is always hidden by a member of the same name.
10441046
* (Either the member is nullary, or the reference is taken as the eta-expansion of the member.)
10451047
*/
1046-
def checkExtensionMethods(sym: Symbol)(using Context): Unit = if sym.is(Extension) then
1047-
extension (tp: Type)
1048-
def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType
1049-
def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1050-
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
1051-
val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver
1052-
val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter
1053-
def hidden =
1054-
target.nonPrivateMember(sym.name)
1055-
.filterWithPredicate:
1056-
member =>
1057-
val memberIsImplicit = member.info.hasImplicitParams
1058-
val paramTps =
1059-
if memberIsImplicit then methTp.stripPoly.firstParamTypes
1060-
else methTp.firstExplicitParamTypes
1061-
1062-
paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || {
1063-
val memberParamTps = member.info.stripPoly.firstParamTypes
1064-
!memberParamTps.isEmpty
1065-
&& memberParamTps.lengthCompare(paramTps) == 0
1066-
&& memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m)
1067-
}
1068-
.exists
1069-
if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden
1070-
then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
1048+
def checkExtensionMethods(sym: Symbol)(using Context): Unit =
1049+
if sym.is(Extension) && !sym.nextOverriddenSymbol.exists then
1050+
extension (tp: Type)
1051+
def strippedResultType = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).resultType
1052+
def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1053+
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
1054+
val target = sym.info.firstExplicitParamTypes.head // required for extension method, the putative receiver
1055+
val methTp = sym.info.strippedResultType // skip leading implicits and the "receiver" parameter
1056+
def hidden =
1057+
target.nonPrivateMember(sym.name)
1058+
.filterWithPredicate:
1059+
member =>
1060+
val memberIsImplicit = member.info.hasImplicitParams
1061+
val paramTps =
1062+
if memberIsImplicit then methTp.stripPoly.firstParamTypes
1063+
else methTp.firstExplicitParamTypes
1064+
1065+
paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || {
1066+
val memberParamTps = member.info.stripPoly.firstParamTypes
1067+
!memberParamTps.isEmpty
1068+
&& memberParamTps.lengthCompare(paramTps) == 0
1069+
&& memberParamTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m)
1070+
}
1071+
.exists
1072+
if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias && hidden
1073+
then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
10711074
end checkExtensionMethods
10721075

10731076
/** 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)