Skip to content

Commit 8bbb0ba

Browse files
authored
Merge pull request #11361 from dotty-staging/drop-javamethod-new-4
Fix overriding Java methods, get rid of JavaMethodType
2 parents e8716c8 + 590d587 commit 8bbb0ba

File tree

19 files changed

+204
-164
lines changed

19 files changed

+204
-164
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ class Definitions {
122122
}
123123
val resParamRef = enterTypeParam(cls, paramNamePrefix ++ "R", Covariant, decls).typeRef
124124
val methodType = MethodType.companion(
125-
isJava = false,
126125
isContextual = name.isContextFunction,
127126
isImplicit = false,
128127
isErased = name.isErasedFunction)

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

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -582,11 +582,30 @@ object Denotations {
582582
*/
583583
def prefix: Type = NoPrefix
584584

585+
/** Either the Scala or Java signature of the info, depending on where the
586+
* symbol is defined.
587+
*
588+
* Invariants:
589+
* - Before erasure, the signature of a denotation is always equal to the
590+
* signature of its corresponding initial denotation.
591+
* - Two distinct overloads will have SymDenotations with distinct
592+
* signatures (the SELECTin tag in Tasty relies on this to refer to an
593+
* overload unambiguously). Note that this only applies to
594+
* SymDenotations, in general we cannot assume that distinct
595+
* SingleDenotations will have distinct signatures (cf #9050).
596+
*/
585597
final def signature(using Context): Signature =
586-
if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation
598+
signature(isJava = !isType && symbol.is(JavaDefined))
599+
600+
/** Overload of `signature` which lets the caller pick between the Java and
601+
* Scala signature of the info. Useful to match denotations defined in
602+
* different classes (see `matchesLoosely`).
603+
*/
604+
def signature(isJava: Boolean)(using Context): Signature =
605+
if (isType) Signature.NotAMethod // don't force info if this is a type denotation
587606
else info match {
588-
case info: MethodicType =>
589-
try info.signature
607+
case info: MethodOrPoly =>
608+
try info.signature(isJava)
590609
catch { // !!! DEBUG
591610
case scala.util.control.NonFatal(ex) =>
592611
report.echo(s"cannot take signature of $info")
@@ -992,34 +1011,45 @@ object Denotations {
9921011
symbol.hasTargetName(other.symbol.targetName)
9931012
&& matchesLoosely(other)
9941013

995-
/** matches without a target name check */
1014+
/** `matches` without a target name check.
1015+
*
1016+
* We consider a Scala method and a Java method to match if they have
1017+
* matching Scala signatures. This allows us to override some Java
1018+
* definitions even if they have a different erasure (see i8615b,
1019+
* i9109b), Erasure takes care of adding any necessary bridge to make
1020+
* this work at runtime.
1021+
*/
9961022
def matchesLoosely(other: SingleDenotation)(using Context): Boolean =
997-
val d = signature.matchDegree(other.signature)
998-
d match
999-
case FullMatch =>
1000-
true
1001-
case MethodNotAMethodMatch =>
1002-
!ctx.erasedTypes && {
1003-
val isJava = symbol.is(JavaDefined)
1004-
val otherIsJava = other.symbol.is(JavaDefined)
1005-
// A Scala zero-parameter method and a Scala non-method always match.
1006-
if !isJava && !otherIsJava then
1007-
true
1008-
// Java allows defining both a field and a zero-parameter method with the same name,
1009-
// so they must not match.
1010-
else if isJava && otherIsJava then
1011-
false
1012-
// A Java field never matches a Scala method.
1013-
else if isJava then
1014-
symbol.is(Method)
1015-
else // otherIsJava
1016-
other.symbol.is(Method)
1017-
}
1018-
case ParamMatch =>
1019-
// The signatures do not tell us enough to be sure about matching
1020-
!ctx.erasedTypes && info.matches(other.info)
1021-
case noMatch =>
1022-
false
1023+
if isType then true
1024+
else
1025+
val isJava = symbol.is(JavaDefined)
1026+
val otherIsJava = other.symbol.is(JavaDefined)
1027+
val useJavaSig = isJava && otherIsJava
1028+
val sig = signature(isJava = useJavaSig)
1029+
val otherSig = other.signature(isJava = useJavaSig)
1030+
sig.matchDegree(otherSig) match
1031+
case FullMatch =>
1032+
true
1033+
case MethodNotAMethodMatch =>
1034+
!ctx.erasedTypes && {
1035+
// A Scala zero-parameter method and a Scala non-method always match.
1036+
if !isJava && !otherIsJava then
1037+
true
1038+
// Java allows defining both a field and a zero-parameter method with the same name,
1039+
// so they must not match.
1040+
else if isJava && otherIsJava then
1041+
false
1042+
// A Java field never matches a Scala method.
1043+
else if isJava then
1044+
symbol.is(Method)
1045+
else // otherIsJava
1046+
other.symbol.is(Method)
1047+
}
1048+
case ParamMatch =>
1049+
// The signatures do not tell us enough to be sure about matching
1050+
!ctx.erasedTypes && info.matches(other.info)
1051+
case noMatch =>
1052+
false
10231053

10241054
def mapInherited(ownDenots: PreDenotation, prevDenots: PreDenotation, pre: Type)(using Context): SingleDenotation =
10251055
if hasUniqueSym && prevDenots.containsSym(symbol) then NoDenotation

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ object NamerOps:
3939
val (isContextual, isImplicit, isErased) =
4040
if params.isEmpty then (false, false, false)
4141
else (params.head.is(Given), params.head.is(Implicit), params.head.is(Erased))
42-
val make = MethodType.companion(isJava = isJava, isContextual = isContextual, isImplicit = isImplicit, isErased = isErased)
42+
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit, isErased = isErased)
4343
if isJava then
4444
for param <- params do
4545
if param.info.isDirectRef(defn.ObjectClass) then param.info = defn.AnyType

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,7 @@ object TypeErasure {
249249
!classify(tp).derivesFrom(defn.ObjectClass) &&
250250
!tp.symbol.is(JavaDefined)
251251
case tp: TypeParamRef =>
252-
!classify(tp).derivesFrom(defn.ObjectClass) &&
253-
!tp.binder.resultType.isJavaMethod
252+
!classify(tp).derivesFrom(defn.ObjectClass)
254253
case tp: TypeAlias => isUnboundedGeneric(tp.alias)
255254
case tp: TypeBounds =>
256255
val upper = classify(tp.hi)
@@ -474,7 +473,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
474473
TypeComparer.orType(this(tp1), this(tp2), isErased = true)
475474
case tp: MethodType =>
476475
def paramErasure(tpToErase: Type) =
477-
erasureFn(tp.isJavaMethod, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
476+
erasureFn(isJava, semiEraseVCs, isConstructor, wildcardOK)(tpToErase)
478477
val (names, formals0) = if (tp.isErasedMethod) (Nil, Nil) else (tp.paramNames, tp.paramInfos)
479478
val formals = formals0.mapConserve(paramErasure)
480479
eraseResult(tp.resultType) match {

0 commit comments

Comments
 (0)