From 6bd8f60b554168a2fafb10f6ff7ac42056b4a3d3 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 29 Dec 2024 11:36:46 -0800 Subject: [PATCH] Tweak ExtensionNullifiedByMember --- .../dotty/tools/dotc/reporting/messages.scala | 11 +++++--- tests/warn/i22267.check | 14 ++++++++++ tests/warn/i22267.scala | 28 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 tests/warn/i22267.check create mode 100644 tests/warn/i22267.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 28a2b5757a93..692b87f68821 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2504,12 +2504,15 @@ class ExtensionNullifiedByMember(method: Symbol, target: Symbol)(using Context) extends Message(ExtensionNullifiedByMemberID): def kind = MessageKind.PotentialIssue def msg(using Context) = - i"""Extension method ${hl(method.name.toString)} will never be selected - |because ${hl(target.name.toString)} already has a member with the same name and compatible parameter types.""" + val targetName = hl(target.name.toString) + i"""Extension method ${hl(method.name.toString)} will never be selected from type $targetName + |because $targetName already has a member with the same name and compatible parameter types.""" def explain(using Context) = - i"""An extension method can be invoked as a regular method, but if that is intended, + i"""Although extensions can be overloaded, they do not overload existing member methods. + |An extension method can be invoked as a regular method, but if that is the intended usage, |it should not be defined as an extension. - |Although extensions can be overloaded, they do not overload existing member methods.""" + | + |The extension may be invoked as though selected from an arbitrary type if conversions are in play.""" class TraitCompanionWithMutableStatic()(using Context) extends SyntaxMsg(TraitCompanionWithMutableStaticID) { diff --git a/tests/warn/i22267.check b/tests/warn/i22267.check new file mode 100644 index 000000000000..a6b1ccbdef52 --- /dev/null +++ b/tests/warn/i22267.check @@ -0,0 +1,14 @@ +-- [E194] Potential Issue Warning: tests/warn/i22267.scala:13:26 ------------------------------------------------------- +13 | extension (self: C) def m(n: Double): Unit = println(2->n) // warn + | ^ + | Extension method m will never be selected from type C + | because C already has a member with the same name and compatible parameter types. + |-------------------------------------------------------------------------------------------------------------------- + | Explanation (enabled by `-explain`) + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Although extensions can be overloaded, they do not overload existing member methods. + | An extension method can be invoked as a regular method, but if that is the intended usage, + | it should not be defined as an extension. + | + | The extension may be invoked as though selected from an arbitrary type if conversions are in play. + -------------------------------------------------------------------------------------------------------------------- diff --git a/tests/warn/i22267.scala b/tests/warn/i22267.scala new file mode 100644 index 000000000000..d1f6699342e9 --- /dev/null +++ b/tests/warn/i22267.scala @@ -0,0 +1,28 @@ +//> using options -explain + +import language.implicitConversions + +case class M[T](value: T) +given [T]: Conversion[M[T], T] = _.value +class C: + def m(n: Double): Unit = println(0->n) +object C: + given Ops = Ops() +class Ops: + extension (self: C) def m(n: Int): Unit = println(1->n) + extension (self: C) def m(n: Double): Unit = println(2->n) // warn + extension (self: C) def m(s: String): Unit = println(3->s) + +@main def test() = + val c = M(C()) + def i = 42 + def pi = 3.14 + c.value.m(i) + c.value.m(pi) + c.m(i) // conversion + c.m(pi) // conversion + c.m("hello, world") // extension + //m(c)(pi) + val c0 = C() + c0.m(pi) + c0.m("hello, world")