Skip to content

Commit

Permalink
Warn universal extensions on opaque types (#22502)
Browse files Browse the repository at this point in the history
Fixes #22232 

Work also done by @hamzaremmal, @julian-a-avar-c and @nmcb

Co-authored-by: Hamza Remmal <hamza@remmal.net>
  • Loading branch information
rochala and hamzaremmal authored Feb 24, 2025
1 parent 9450855 commit 7d79c56
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 2 deletions.
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ object RefChecks {
def explicit = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true)
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
val explicitInfo = sym.info.explicit // consider explicit value params
val target = explicitInfo.firstParamTypes.head // required for extension method, the putative receiver
val target = explicitInfo.firstParamTypes.head.typeSymbol.info // required for extension method, the putative receiver
val methTp = explicitInfo.resultType // skip leading implicits and the "receiver" parameter
def hidden =
target.nonPrivateMember(sym.name)
Expand Down Expand Up @@ -1200,7 +1200,7 @@ object RefChecks {
sym.owner.info.member(getterName)
if getterDenot.exists
then report.warning(ExtensionHasDefault(sym), getterDenot.symbol.srcPos)
if !target.typeSymbol.isOpaqueAlias && !sym.nextOverriddenSymbol.exists && hidden
if !sym.nextOverriddenSymbol.exists && hidden
then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
end checkExtensionMethods

Expand Down
28 changes: 28 additions & 0 deletions tests/warn/i22232.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- [E194] Potential Issue Warning: tests/warn/i22232.scala:3:23 --------------------------------------------------------
3 | extension (c: C) def equals(that: Any): Boolean = false // warn
| ^
| Extension method equals will never be selected from type C
| because C 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/i22232.scala:9:25 --------------------------------------------------------
9 | extension (d: D) def equals(that: Any): Boolean = false // warn
| ^
| Extension method equals will never be selected from type C
| because C 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/i22232.scala:13:38 -------------------------------------------------------
13 | extension (arr: MyString[Byte]) def length: Int = 0 // warn
| ^
| 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/i22232.scala:17:46 -------------------------------------------------------
17 | extension [T <: MyString[Byte]](arr: T) def length: Int = 0 // warn
| ^
| 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`
32 changes: 32 additions & 0 deletions tests/warn/i22232.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class C
object C:
extension (c: C) def equals(that: Any): Boolean = false // warn

object X:
class C
opaque type D <: C = C
object D:
extension (d: D) def equals(that: Any): Boolean = false // warn

object Upperbound1:
opaque type MyString[+T] <: String = String
extension (arr: MyString[Byte]) def length: Int = 0 // warn

object Upperbound2:
opaque type MyString[+T] <: String = String
extension [T <: MyString[Byte]](arr: T) def length: Int = 0 // warn

object Upperbound3:
opaque type MyString[+T] <: String = String
extension [T](arr: T) def length: Int = 0 // nowarn

object NonUpperbound1:
opaque type MyString[+T] = String
extension (arr: MyString[Byte]) def length: Int = 0 // nowarn
object NonUpperbound2:
opaque type MyString[+T] = String
extension [T <: MyString[Byte]](arr: T) def length2: Int = 0 // nowarn

object NonUpperbound3:
opaque type MyString[+T] = String
extension [T](arr: T) def length: Int = 0 // nowarn

0 comments on commit 7d79c56

Please sign in to comment.