diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 3393378617d6..bcf92eb2721f 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -1043,8 +1043,8 @@ object RefChecks { * This check is suppressed if the method is an override. (Because the type of the receiver * may be narrower in the override.) * - * If the extension method is nullary, it is always hidden by a member of the same name. - * (Either the member is nullary, or the reference is taken as the eta-expansion of the member.) + * If the extension method is nilary, it is always hidden by a member of the same name. + * (Either the member is nilary, or the reference is taken as the eta-expansion of the member.) * * This check is in lieu of a more expensive use-site check that an application failed to use an extension. * That check would account for accessibility and opacity. As a limitation, this check considers @@ -1068,25 +1068,29 @@ object RefChecks { extension (tp: Type) def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true) def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false } + def isNilary = tp.stripPoly match { case mt: MethodType => false case _ => true } val explicitInfo = sym.info.explicit // consider explicit value params - val target0 = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver - val target = target0.dealiasKeepOpaques.typeSymbol.info - val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter - def memberMatchesMethod(member: Denotation) = + def memberHidesMethod(member: Denotation): Boolean = + val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter + if methTp.isNilary then + return true // extension without parens is always hidden by a member of same name val memberIsImplicit = member.info.hasImplicitParams - val paramTps = - if memberIsImplicit then methTp.stripPoly.firstParamTypes - else methTp.explicit.firstParamTypes inline def paramsCorrespond = + val paramTps = + if memberIsImplicit then methTp.stripPoly.firstParamTypes + else methTp.explicit.firstParamTypes val memberParamTps = member.info.stripPoly.firstParamTypes memberParamTps.corresponds(paramTps): (m, x) => m.typeSymbol.denot.isOpaqueAlias == x.typeSymbol.denot.isOpaqueAlias && (x frozen_<:< m) - paramTps.isEmpty || memberIsImplicit && !methTp.hasImplicitParams || paramsCorrespond - def hidden = - target.nonPrivateMember(sym.name) - .filterWithPredicate: member => - member.symbol.isPublic && memberMatchesMethod(member) - .exists + memberIsImplicit && !methTp.hasImplicitParams || paramsCorrespond + def targetOfHiddenExtension: Symbol = + val target = + val target0 = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver + target0.dealiasKeepOpaques.typeSymbol.info + val member = target.nonPrivateMember(sym.name) + .filterWithPredicate: member => + member.symbol.isPublic && memberHidesMethod(member) + if member.exists then target.typeSymbol else NoSymbol if sym.is(HasDefaultParams) then val getterDenot = val receiverName = explicitInfo.firstParamNames.head @@ -1095,8 +1099,10 @@ object RefChecks { sym.owner.info.member(getterName) if getterDenot.exists then report.warning(ExtensionHasDefault(sym), getterDenot.symbol.srcPos) - if !sym.nextOverriddenSymbol.exists && hidden - then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos) + if !sym.nextOverriddenSymbol.exists then + val target = targetOfHiddenExtension + if target.exists then + report.warning(ExtensionNullifiedByMember(sym, target), sym.srcPos) end checkExtensionMethods /** Verify that references in the user-defined `@implicitNotFound` message are valid. diff --git a/tests/warn/i16743.check b/tests/warn/i16743.check deleted file mode 100644 index 9fdf80e71f2b..000000000000 --- a/tests/warn/i16743.check +++ /dev/null @@ -1,91 +0,0 @@ --- [E194] Potential Issue Warning: tests/warn/i16743.scala:90:8 -------------------------------------------------------- -90 | def length() = 42 // warn This extension method will be shadowed by .length() on String. - | ^ - | Extension method length will never be selected from type String - | because String already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:30:6 -------------------------------------------------------- -30 | def t = 27 // warn - | ^ - | Extension method t will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:32:6 -------------------------------------------------------- -32 | def g(x: String)(i: Int): String = x*i // warn - | ^ - | Extension method g will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:33:6 -------------------------------------------------------- -33 | def h(x: String): String = x // warn - | ^ - | Extension method h will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:35:6 -------------------------------------------------------- -35 | def j(x: Any, y: Int): String = (x.toString)*y // warn - | ^ - | Extension method j will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:36:6 -------------------------------------------------------- -36 | def k(x: String): String = x // warn - | ^ - | Extension method k will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:38:6 -------------------------------------------------------- -38 | def m(using String): String = "m" + summon[String] // warn - | ^ - | Extension method m will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:39:6 -------------------------------------------------------- -39 | def n(using String): String = "n" + summon[String] // warn - | ^ - | Extension method n will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:40:6 -------------------------------------------------------- -40 | def o: String = "42" // warn - | ^ - | Extension method o will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:41:6 -------------------------------------------------------- -41 | def u: Int = 27 // warn - | ^ - | Extension method u will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:44:6 -------------------------------------------------------- -44 | def at: Int = 42 // warn - | ^ - | Extension method at will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:46:6 -------------------------------------------------------- -46 | def x(using String)(n: Int): Int = summon[String].toInt + n // warn - | ^ - | Extension method x will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` --- [E194] Potential Issue Warning: tests/warn/i16743.scala:47:6 -------------------------------------------------------- -47 | def y(using String)(s: String): String = s + summon[String] // warn - | ^ - | Extension method y will never be selected from type T - | because T already has a member with the same name and compatible parameter types. - | - | longer explanation available when compiling with `-explain` diff --git a/tests/warn/i16743.scala b/tests/warn/i16743.scala index 213e22ff4cb4..cca0ecbce90e 100644 --- a/tests/warn/i16743.scala +++ b/tests/warn/i16743.scala @@ -25,6 +25,7 @@ trait T: def x(n: Int): Int = 42 + n def y(n: Int): Int = u + n def y(s: String): String = s + u + def z(s: String): String = s + m extension (_t: T) def t = 27 // warn @@ -45,6 +46,7 @@ extension (_t: T) def w(using String)(n: String): Int = (summon[String] + n).toInt def x(using String)(n: Int): Int = summon[String].toInt + n // warn def y(using String)(s: String): String = s + summon[String] // warn + def z(): String = "extension" // deferred extension is defined in subclass trait Foo: