Skip to content

Commit 24ea6a1

Browse files
authored
Merge pull request scala#11120 from som-snytt/issue/13111-dubious-overload-followup
Warn confusing member when contributing it
2 parents 35e6ee5 + 87490e6 commit 24ea6a1

File tree

3 files changed

+56
-32
lines changed

3 files changed

+56
-32
lines changed

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ abstract class RefChecks extends Transform {
160160
})
161161
}
162162
}
163+
// warn if clazz defines nullary member `m` where `def m(implicit t: T)` is also defined, or conversely.
164+
// That is confusing because the expression `m` might invoke either member.
163165
private def checkDubiousOverloads(clazz: Symbol): Unit = if (settings.warnDubiousOverload) {
164166
// nullary members or methods with leading implicit params
165167
def ofInterest(tp: Type): Boolean = tp match {
@@ -173,6 +175,12 @@ abstract class RefChecks extends Transform {
173175
case PolyType(_, rt) => isNullary(rt)
174176
case _ => true // includes NullaryMethodType
175177
}
178+
// if all the competing symbols are members of a base class of clazz, don't warn in clazz, since the base warns
179+
def warnable(syms: List[Symbol]): Boolean =
180+
!clazz.baseClasses.drop(1).exists { base =>
181+
val members = base.info.members
182+
syms.forall(sym => members.lookupSymbolEntry(sym) != null)
183+
}
176184
def warnDubious(sym: Symbol, alts: List[Symbol]): Unit = {
177185
val usage = if (sym.isMethod && !sym.isGetter) "Calls to parameterless" else "Usages of"
178186
val simpl = "a single implicit parameter list"
@@ -205,27 +213,28 @@ abstract class RefChecks extends Transform {
205213
else isCompetitive(syms, sawNlly, sawNonNlly)
206214
case _ => false
207215
})
208-
for ((_, syms) <- byName if syms.lengthCompare(1) > 0 && isCompetitive(syms, sawNlly=false, sawNonNlly=false)) {
209-
val (nullaries, alts) = syms.partition(sym => isNullary(sym.info))
210-
//assert(!alts.isEmpty)
211-
nullaries match {
212-
case nullary :: Nil => warnDubious(nullary, syms)
213-
case nullaries =>
214-
//assert(!nullaries.isEmpty)
215-
val dealiased =
216-
nullaries.find(_.isPrivateLocal) match {
217-
case Some(local) =>
218-
nullaries.find(sym => sym.isAccessor && sym.accessed == local) match {
219-
case Some(accessor) => nullaries.filter(_ != local) // drop local if it has an accessor
220-
case _ => nullaries
221-
}
222-
case _ => nullaries
223-
}
224-
// there are multiple exactly for a private local and an inherited member
225-
for (nullary <- dealiased)
226-
warnDubious(nullary, nullary :: alts)
216+
for ((_, syms) <- byName)
217+
if (syms.lengthCompare(1) > 0 && isCompetitive(syms, sawNlly = false, sawNonNlly = false) && warnable(syms)) {
218+
val (nullaries, alts) = syms.partition(sym => isNullary(sym.info))
219+
//assert(!alts.isEmpty)
220+
nullaries match {
221+
case nullary :: Nil => warnDubious(nullary, alts)
222+
case nullaries =>
223+
//assert(!nullaries.isEmpty)
224+
val dealiased =
225+
nullaries.find(_.isPrivateLocal) match {
226+
case Some(local) =>
227+
nullaries.find(sym => sym.isAccessor && sym.accessed == local) match {
228+
case Some(accessor) => nullaries.filter(_ != local) // drop local if it has an accessor
229+
case _ => nullaries
230+
}
231+
case _ => nullaries
232+
}
233+
// there are multiple exactly for a private local and an inherited member
234+
for (nullary <- dealiased)
235+
warnDubious(nullary, nullary :: alts) // add (other) nullary to list of alts to show as overloads
236+
}
227237
}
228-
}
229238
}
230239

231240
// Override checking ------------------------------------------------------------

test/files/neg/t7415.check

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,35 @@ t7415.scala:14: warning: Usages of value foo will be easy to mistake for calls t
77
t7415.scala:18: warning: Usages of value foo will be easy to mistake for calls to def foo(implicit a: T): Int, which has a single implicit parameter list.
88
private[this] val foo = 42 // warn
99
^
10-
t7415.scala:31: warning: Calls to parameterless method foo will be easy to mistake for calls to def foo(implicit a: T): Int, which has a single implicit parameter list.
10+
t7415.scala:33: warning: Calls to parameterless method foo will be easy to mistake for calls to def foo(implicit a: T): Int, which has a single implicit parameter list.
1111
class Mixed extends Base with T1 // warn here
1212
^
13-
t7415.scala:41: warning: Usages of value foo will be easy to mistake for calls to overloads which have a single implicit parameter list:
13+
t7415.scala:36: warning: Calls to parameterless method foo will be easy to mistake for calls to def foo(implicit a: T): Int, which has a single implicit parameter list.
14+
def foo(implicit a: T) = 0 // warn although x.foo picks this one
15+
^
16+
t7415.scala:47: warning: Usages of value foo will be easy to mistake for calls to overloads which have a single implicit parameter list:
1417
def foo(implicit e: String): Int
1518
def foo(implicit e: Int): Int
1619
val foo = 0 // warn
1720
^
18-
t7415.scala:54: warning: Usages of value x will be easy to mistake for calls to def x(implicit t: T): Int, which has a single implicit parameter list.
21+
t7415.scala:60: warning: Usages of value x will be easy to mistake for calls to def x(implicit t: T): Int, which has a single implicit parameter list.
1922
def x(implicit t: T) = 27 // warn
2023
^
21-
t7415.scala:65: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
24+
t7415.scala:71: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
2225
class R(val i: Int) extends Q // warn
2326
^
24-
t7415.scala:66: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
27+
t7415.scala:72: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
2528
class S(i: Int) extends R(i) { // warn
2629
^
27-
t7415.scala:66: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
30+
t7415.scala:72: warning: Usages of value i will be easy to mistake for calls to def i(implicit t: T): Int, which has a single implicit parameter list.
2831
class S(i: Int) extends R(i) { // warn
2932
^
30-
t7415.scala:76: warning: Calls to parameterless method f will be easy to mistake for calls to def f[A](implicit t: T): Int, which has a single implicit parameter list.
33+
t7415.scala:82: warning: Calls to parameterless method f will be easy to mistake for calls to def f[A](implicit t: T): Int, which has a single implicit parameter list.
3134
def f[A] = 27 // warn
3235
^
33-
t7415.scala:82: warning: Calls to parameterless method foo will be easy to mistake for calls to def foo(implicit a: T): Int, which has a single implicit parameter list.
34-
val d1 = new Derived1 {} // warn
35-
^
36+
t7415.scala:88: warning: Usages of value an will be easy to mistake for calls to def an[A](implicit evidence$1: scala.reflect.ClassTag[A]): Unit, which has a single implicit parameter list.
37+
val an = new Object // warn
38+
^
3639
error: No warnings can be incurred under -Werror.
37-
11 warnings
40+
12 warnings
3841
1 error

test/files/neg/t7415.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ class C2 extends Derived2 {
2424
}
2525
*/
2626

27+
class Derived extends Derived2 // no warn, all foo are already members of Derived2
28+
2729
trait T1 {
2830
def foo = 0
2931
}
3032

3133
class Mixed extends Base with T1 // warn here
3234

35+
class Inverted extends T1 {
36+
def foo(implicit a: T) = 0 // warn although x.foo picks this one
37+
}
38+
3339
class D {
3440
def foo(a: List[Int])(implicit d: DummyImplicit) = 0
3541
def foo(a: List[String]) = 1
@@ -77,9 +83,15 @@ trait PDerived extends PBase {
7783
def g[A] = f[A] // no warn
7884
}
7985

86+
trait Matchers {
87+
def an[A: reflect.ClassTag] = ()
88+
val an = new Object // warn
89+
}
90+
object InnocentTest extends Matchers
91+
8092
object Test extends App {
8193
implicit val t: T = new T {}
82-
val d1 = new Derived1 {} // warn
94+
val d1 = new Derived1 {} // no warn innocent client, already warned in evil parent
8395
println(d1.foo) // !
8496
val more = new MoreInspiration
8597
println(more.foo) // ?

0 commit comments

Comments
 (0)