Skip to content

Commit 8138eb4

Browse files
committed
RefChecks cleanuo
Remove illogical conditions that suppressed certain checks. Replace them by a separate condition that certain override checks are suppressed if the types of the members do not match (i.e. it's just the signatures that match but not the types). In that case, we have arguably overshot with declaring an override. Bridge generation is also suppressed in this case. Scala 2 behaves effectively the same way, by never taking signatures into account.
1 parent e008f6e commit 8138eb4

File tree

8 files changed

+86
-32
lines changed

8 files changed

+86
-32
lines changed

compiler/src/dotty/tools/dotc/transform/Bridges.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
3636
!sym.isOneOf(MethodOrModule) || super.exclude(sym)
3737
}
3838

39-
//val site = root.thisType
39+
val site = root.thisType
4040

4141
private var toBeRemoved = immutable.Set[Symbol]()
4242
private val bridges = mutable.ListBuffer[Tree]()
@@ -77,7 +77,13 @@ class Bridges(root: ClassSymbol, thisPhase: DenotTransformer)(using Context) {
7777
|clashes with definition of the member itself; both have erased type ${info(member)(using elimErasedCtx)}."""",
7878
bridgePosFor(member))
7979
}
80-
else if (!bridgeExists)
80+
else if !inContext(preErasureCtx)(site.memberInfo(member).matches(site.memberInfo(other))) then
81+
// Neither symbol signatures nor pre-erasure types seen from root match; this means
82+
// according to Scala 2 semantics there is no override.
83+
// A bridge might introduce a classcast exception.
84+
// Example where this was observed: run/i12828a.scala and MapView in stdlib213
85+
report.log(i"suppress bridge in $root for ${member} in ${member.owner} and ${other.showLocated} since member infos ${site.memberInfo(member)} and ${site.memberInfo(other)} do not match")
86+
else if !bridgeExists then
8187
addBridge(member, other)
8288
}
8389

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

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,13 @@ object RefChecks {
323323
overrideErrorMsg("no longer has compatible type"),
324324
(if (member.owner == clazz) member else clazz).srcPos))
325325

326+
/** Do types of `member` and `other` as seen from `self` match?
327+
* If not we treat them as not a real override and don't issue certain
328+
* error messages. Also, bridges are not generated in this case.
329+
*/
330+
def trueMatch: Boolean =
331+
memberTp(self).matches(otherTp(self))
332+
326333
def emitOverrideError(fullmsg: Message) =
327334
if (!(hasErrors && member.is(Synthetic) && member.is(Module))) {
328335
// suppress errors relating toi synthetic companion objects if other override
@@ -360,31 +367,6 @@ object RefChecks {
360367

361368
//Console.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG
362369

363-
// return if we already checked this combination elsewhere
364-
if (member.owner != clazz) {
365-
def deferredCheck = member.is(Deferred) || !other.is(Deferred)
366-
def subOther(s: Symbol) = s derivesFrom other.owner
367-
def subMember(s: Symbol) = s derivesFrom member.owner
368-
369-
if (subOther(member.owner) && deferredCheck)
370-
//println(i"skip 1 ${member.showLocated}, ${other.showLocated}")
371-
//Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG
372-
return
373-
/*
374-
val parentSymbols = clazz.info.parents.map(_.typeSymbol)
375-
def matchIn(parent: Symbol): Boolean = considerMatching(member, other, parent.thisType)
376-
if parentSymbols.exists(p =>
377-
subOther(p) && subMember(p) && deferredCheck && matchIn(p))
378-
then
379-
println(i"skip 2 ${member.showLocated}, ${other.showLocated}")
380-
//Console.println(infoString(member) + " shadows2 " + infoString(other) + " in " + clazz);//DEBUG
381-
return
382-
if parentSymbols.forall(p => subOther(p) == subMember(p) && matchIn(p)) then
383-
println(i"skip 3 ${member.showLocated}, ${other.showLocated}")
384-
//Console.println(infoString(member) + " shadows " + infoString(other) + " in " + clazz);//DEBUG
385-
return*/
386-
}
387-
388370
/* Is the intersection between given two lists of overridden symbols empty? */
389371
def intersectionIsEmpty(syms1: Iterator[Symbol], syms2: Iterator[Symbol]) = {
390372
val set2 = syms2.toSet
@@ -419,7 +401,7 @@ object RefChecks {
419401
overrideError("cannot be used here - class definitions cannot be overridden")
420402
else if (!other.is(Deferred) && member.isClass)
421403
overrideError("cannot be used here - classes can only override abstract types")
422-
else if (other.isEffectivelyFinal) // (1.2)
404+
else if other.isEffectivelyFinal && trueMatch then // (1.2)
423405
overrideError(i"cannot override final member ${other.showLocated}")
424406
else if (member.is(ExtensionMethod) && !other.is(ExtensionMethod)) // (1.3)
425407
overrideError("is an extension method, cannot override a normal method")
@@ -440,15 +422,18 @@ object RefChecks {
440422
member.setFlag(Override)
441423
else if (member.isType && self.memberInfo(member) =:= self.memberInfo(other))
442424
() // OK, don't complain about type aliases which are equal
443-
else if (member.owner != clazz && other.owner != clazz &&
444-
!(other.owner derivesFrom member.owner))
425+
else if member.owner != clazz
426+
&& other.owner != clazz
427+
&& !other.owner.derivesFrom(member.owner)
428+
&& trueMatch
429+
then
445430
emitOverrideError(
446431
s"$clazz inherits conflicting members:\n "
447432
+ infoStringWithLocation(other) + " and\n " + infoStringWithLocation(member)
448433
+ "\n(Note: this can be resolved by declaring an override in " + clazz + ".)")
449434
else if member.is(Exported) then
450435
overrideError("cannot override since it comes from an export")
451-
else
436+
else if trueMatch then
452437
overrideError("needs `override` modifier")
453438
else if (other.is(AbsOverride) && other.isIncompleteIn(clazz) && !member.is(AbsOverride))
454439
overrideError("needs `abstract override` modifiers")

tests/neg/i12828c.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
abstract class Foo[A] {
2+
def foo(x: A): Unit
3+
}
4+
abstract class Bar[A] extends Foo[A] {
5+
def foo(x: A with String): Unit = println(x.toUpperCase)
6+
}
7+
object Baz extends Bar[Int] // error overriding foo: incompatible type
8+
// Scala 2 gives: object creation impossible. Missing implementation for `foo`
9+
10+
object Test {
11+
def main(args: Array[String]) = Baz.foo(42)
12+
}

tests/neg/i12828d.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait A[X] {
2+
def foo(x: X): Unit =
3+
println("A.foo")
4+
}
5+
trait B[X] extends A[X] {
6+
def foo(x: Int): Unit =
7+
println("B.foo")
8+
}
9+
object C extends B[Int] // error: conflicting members
10+
// Scala 2: same
11+
12+
object Test {
13+
def main(args: Array[String]) = {
14+
C.foo(1)
15+
val a: A[Int] = C
16+
a.foo(1)
17+
}
18+
}

tests/neg/varargs-annot-2.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import annotation.varargs
2+
3+
trait C {
4+
@varargs def v(i: Int*) = ()
5+
}
6+
7+
class D extends C { // error: name clash between defined and inherited member
8+
def v(i: Array[Int]) = ()
9+
}

tests/neg/varargs-annot.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Test {
1717

1818
class D extends C {
1919
override def v(i: Int*) = () // error
20-
def v(i: Array[Int]) = () // error
20+
def v(i: Array[Int]) = () // ok, reported when used alone (see varargs-annot-2.scala)
2121
}
2222

2323
@varargs def nov(a: Int) = 0 // error: A method without repeated parameters cannot be annotated with @varargs

tests/run/i12828a.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait Foo[A] {
2+
def foo(x: A): Unit = ()
3+
}
4+
trait Bar[A] extends Foo[A] {
5+
def foo(x: A with String): Unit = println(x.toUpperCase)
6+
}
7+
object Baz extends Bar[Int] // was: error: Baz inherits conflicting members, now like Scala 2
8+
// Scala 2 compiles and runs
9+
10+
object Test {
11+
def main(args: Array[String]) = Baz.foo(42)
12+
}

tests/run/i12828b.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Foo[A] {
2+
def foo(x: A): Unit = ()
3+
}
4+
class Bar[A] extends Foo[A] {
5+
def foo(x: A with String): Unit = println(x.toUpperCase)
6+
}
7+
object Baz extends Bar[Int] // was error: Baz inherits conflicting members, now like Scalac
8+
// Scala 2 compiles and runs
9+
10+
object Test {
11+
def main(args: Array[String]) = Baz.foo(42)
12+
}

0 commit comments

Comments
 (0)