Skip to content

Commit 97bf8a3

Browse files
committed
Improve
1 parent 46d6a58 commit 97bf8a3

File tree

4 files changed

+68
-33
lines changed

4 files changed

+68
-33
lines changed

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

+17-7
Original file line numberDiff line numberDiff line change
@@ -1052,20 +1052,30 @@ object RefChecks {
10521052
* An extension method is hidden if it does not offer a parameter that is not subsumed
10531053
* by the corresponding parameter of the member (or of all alternatives of an overload).
10541054
*
1055-
* If the member has no parameters and the extension method has only implicit parameters,
1056-
* then warn that the extension is shadowed unless called with explicit arguments.
1055+
* If the member has implicit parameters, then the application must supply explicit `using`
1056+
* arguments to select an extension method. The reason is that if the arguments are not
1057+
* supplied implicitly, typechecking fails and stops. But with explicit arguments, extensions
1058+
* may be considered, and of course the extension must also accept implicit parameters.
1059+
*
1060+
* If the extension method is nullary, it is always hidden by a member of the same name.
10571061
*/
10581062
def checkExtensionMethods(sym: Symbol)(using Context): Unit = if sym.is(Extension) then
1059-
extension (tp: Type) def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1063+
extension (tp: Type)
1064+
def firstExplicitParamTypes = Applications.stripImplicit(tp.stripPoly, wildcardOnly = true).firstParamTypes
1065+
def hasImplicitParams = tp.stripPoly match { case mt: MethodType => mt.isImplicitMethod case _ => false }
10601066
val target = sym.info.firstParamTypes.head // required for extension method
10611067
if !target.typeSymbol.denot.isAliasType && !target.typeSymbol.denot.isOpaqueAlias then
1062-
val paramTps = sym.denot.info.resultType.firstExplicitParamTypes
1068+
val methTp = sym.denot.info.resultType
1069+
val paramTps = methTp.firstExplicitParamTypes
10631070
val hidden =
10641071
target.nonPrivateMember(sym.name)
10651072
.filterWithPredicate:
1066-
_.info.firstExplicitParamTypes
1067-
.lazyZip(paramTps)
1068-
.forall((m, x) => x frozen_<:< m)
1073+
member => paramTps.isEmpty || member.info.hasImplicitParams && !methTp.hasImplicitParams || {
1074+
val memberTps = member.info.firstExplicitParamTypes
1075+
!memberTps.isEmpty
1076+
&& memberTps.lengthCompare(paramTps) == 0
1077+
&& memberTps.lazyZip(paramTps).forall((m, x) => x frozen_<:< m)
1078+
}
10691079
.exists
10701080
if hidden then report.warning(ExtensionNullifiedByMember(sym, target.typeSymbol), sym.srcPos)
10711081

scaladoc-testcases/src/tests/implicitConversions.scala

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ given Conversion[A, B] with {
66
def apply(a: A): B = ???
77
}
88

9+
@annotation.nowarn
910
extension (a: A) def extended_bar(): String = ???
1011

1112
class A {

tests/neg/i16743.check

+26-20
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,66 @@
1-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:26:6 -----------------------------------------------------------
2-
26 | def t = 27 // error
1+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:29:6 -----------------------------------------------------------
2+
29 | def t = 27 // error
33
| ^
44
| Suspicious extension t is already a member of T
55
|
66
| longer explanation available when compiling with `-explain`
7-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:28:6 -----------------------------------------------------------
8-
28 | def g(x: String)(i: Int): String = x*i // error
7+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:31:6 -----------------------------------------------------------
8+
31 | def g(x: String)(i: Int): String = x*i // error
99
| ^
1010
| Suspicious extension g is already a member of T
1111
|
1212
| longer explanation available when compiling with `-explain`
13-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:29:6 -----------------------------------------------------------
14-
29 | def h(x: String): String = x // error
13+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:32:6 -----------------------------------------------------------
14+
32 | def h(x: String): String = x // error
1515
| ^
1616
| Suspicious extension h is already a member of T
1717
|
1818
| longer explanation available when compiling with `-explain`
19-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:31:6 -----------------------------------------------------------
20-
31 | def j(x: Any, y: Int): String = (x.toString)*y // error
19+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:34:6 -----------------------------------------------------------
20+
34 | def j(x: Any, y: Int): String = (x.toString)*y // error
2121
| ^
2222
| Suspicious extension j is already a member of T
2323
|
2424
| longer explanation available when compiling with `-explain`
25-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:32:6 -----------------------------------------------------------
26-
32 | def k(x: String): String = x // error
25+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:35:6 -----------------------------------------------------------
26+
35 | def k(x: String): String = x // error
2727
| ^
2828
| Suspicious extension k is already a member of T
2929
|
3030
| longer explanation available when compiling with `-explain`
31-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:33:6 -----------------------------------------------------------
32-
33 | def l(using String): String = summon[String] // error: can't be called implicitly
31+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:36:6 -----------------------------------------------------------
32+
36 | def l(using String): String = summon[String] // error: can't be called implicitly
3333
| ^
3434
| Suspicious extension l is already a member of T
3535
|
3636
| longer explanation available when compiling with `-explain`
37-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:34:6 -----------------------------------------------------------
38-
34 | def m(using String): String = "m" + summon[String] // error
37+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:37:6 -----------------------------------------------------------
38+
37 | def m(using String): String = "m" + summon[String] // error
3939
| ^
4040
| Suspicious extension m is already a member of T
4141
|
4242
| longer explanation available when compiling with `-explain`
43-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:35:6 -----------------------------------------------------------
44-
35 | def n(using String): String = "n" + summon[String] // error
43+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:38:6 -----------------------------------------------------------
44+
38 | def n(using String): String = "n" + summon[String] // error
4545
| ^
4646
| Suspicious extension n is already a member of T
4747
|
4848
| longer explanation available when compiling with `-explain`
49-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:36:6 -----------------------------------------------------------
50-
36 | def o: String = "42" // error
49+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:39:6 -----------------------------------------------------------
50+
39 | def o: String = "42" // error
5151
| ^
5252
| Suspicious extension o is already a member of T
5353
|
5454
| longer explanation available when compiling with `-explain`
55-
-- [E193] Potential Issue Error: tests/neg/i16743.scala:37:6 -----------------------------------------------------------
56-
37 | def u: Int = 27 // error
55+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:40:6 -----------------------------------------------------------
56+
40 | def u: Int = 27 // error
5757
| ^
5858
| Suspicious extension u is already a member of T
5959
|
6060
| longer explanation available when compiling with `-explain`
61+
-- [E193] Potential Issue Error: tests/neg/i16743.scala:43:6 -----------------------------------------------------------
62+
43 | def at: Int = 42 // error
63+
| ^
64+
| Suspicious extension at is already a member of T
65+
|
66+
| longer explanation available when compiling with `-explain`

tests/neg/i16743.scala

+24-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ trait T:
2121
def u(n: Int): Int = u + n
2222
def v(n: Int): Int = u + n
2323
def v(s: String): String = s + u
24+
def end: Int = 42
25+
def at(n: Int) = n
26+
def w(n: Int): Int = 42 + n
2427

2528
extension (_t: T)
2629
def t = 27 // error
@@ -36,6 +39,9 @@ extension (_t: T)
3639
def o: String = "42" // error
3740
def u: Int = 27 // error
3841
def v(d: Double) = 3.14
42+
def end(n: Int): Int = 42 + n
43+
def at: Int = 42 // error
44+
def w(using String)(n: String): Int = (summon[String] + n).toInt
3945

4046
// deferred extension is defined in subclass
4147
trait Foo:
@@ -62,9 +68,21 @@ class Result:
6268
println(x.i("hi", 5)) // OK!
6369
println(x.j("hi", 5)) // member!
6470
println(x.k)
65-
println(x.l(using "x"))
66-
println(x.l)
67-
println(x.m(using "x"))
68-
println(x.m(2))
69-
println(x.n) // OK just checks
70-
println(x.n(using "x")) // also just checks
71+
//println(x.k("hi")) // no, implicit is either omitted (supplied implicitly) or explicitly (using foo)
72+
println(x.l) // usual, invokes member
73+
println(x.l(using "x")) // explicit, member doesn't check, try extension
74+
println(x.m(using "x")) // same idea as previous, except member takes no implicits or any params
75+
println(x.m(2)) // member checks by adapting result
76+
println(x.n) // Result
77+
println(x.n.apply) // apply Result with given
78+
println(x.n(using "x")) // apply Result explicitly, not extension
79+
println(x.end(2))
80+
println(x.at(2))
81+
println {
82+
val p = x.at
83+
p(2)
84+
}
85+
println {
86+
given String = "42"
87+
x.w("27")
88+
}

0 commit comments

Comments
 (0)