Skip to content

Commit d842da2

Browse files
committed
Fix scala#9392: Allow overriding a Java method when a same-named field is present
In scala#9126, Java fields were marked effectively finals to prevent false overrides. This poses a problem when a Java field and method of the same name are present, because a Scala val or def will match both of these according to Denotation#matches. We could tweak `matches` further to not consider the Java field to match any Scala definition, but that might introduce new problems (we couldn't trust `FullMatch` anymore and would need to check the info of any Java symbol which might cause cycles, we would also probably need to tweak overloading resolution to avoid ambiguity when trying to decide whether to select the Java field or the Scala override of the Java method). This commit takes a different approach: we allow a val or def to match a Java field, but we tweak the logic that checks whether the `override` modifier is correctly used to disallow definitions that _only_ match a Java field (thus preventing tests/neg/i9115 from compiling), while letting through definitions that both match a Java field and something else (thus making tests/pos/i9392 compile). This is all a bit messy but I can't think of a better solution which wouldn't be significantly more complicated.
1 parent 0f1a23e commit d842da2

File tree

4 files changed

+27
-3
lines changed

4 files changed

+27
-3
lines changed

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,6 @@ object SymDenotations {
10661066
final def isEffectivelyFinal(using Context): Boolean =
10671067
isOneOf(EffectivelyFinalFlags)
10681068
|| is(Inline, butNot = Deferred)
1069-
|| is(JavaDefinedVal, butNot = Method)
10701069
|| !owner.isExtensibleClass
10711070

10721071
/** A class is effectively sealed if has the `final` or `sealed` modifier, or it

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -778,8 +778,10 @@ object RefChecks {
778778
)
779779
def classDecls = inclazz.info.nonPrivateDecl(member.name)
780780

781-
(inclazz != clazz) &&
782-
classDecls.hasAltWith(d => isSignatureMatch(d.symbol) && javaAccessCheck(d.symbol))
781+
(inclazz != clazz) && classDecls.hasAltWith(d =>
782+
isSignatureMatch(d.symbol) && javaAccessCheck(d.symbol) &&
783+
!d.symbol.is(JavaDefinedVal, butNot = Method) // Java fields cannot be overriden
784+
)
783785
}
784786

785787
// 4. Check that every defined member with an `override` modifier overrides some other member.

tests/pos/i9392/J.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package pkg;
2+
3+
public class J {
4+
int i = 0;
5+
public int i() { return 1; }
6+
}

tests/pos/i9392/S.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class S1 extends pkg.J {
2+
override def i(): Int = 2
3+
}
4+
5+
class S2 extends pkg.J {
6+
override def i: Int = 2
7+
}
8+
object Test {
9+
val s1 = new S1
10+
11+
val i1 = s1.i
12+
val i2 = s1.i()
13+
14+
val s2 = new S2
15+
16+
val i3 = s2.i
17+
}

0 commit comments

Comments
 (0)