Change "most specific return type" definition for fake overrides.
Given overridden descriptors D = d[i]. 1. Find D*, subset of D: returnType(d* from D*) <: returnType(d) for each d from D. Always prefer var to val. 2. Prefer non-flexible return type to flexible. Check for var/val overrides properly (NB: this will report PROPERTY_TYPE_MISMATCH_ON_OVERRIDE for all properties, not just overrides involving vars as it was before).
This commit is contained in:
@@ -499,7 +499,7 @@ public class OverrideResolver {
|
||||
Set<CallableMemberDescriptor> relevantDirectlyOverridden =
|
||||
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations);
|
||||
|
||||
checkInheritedDescriptorsGroup(relevantDirectlyOverridden, reportingStrategy);
|
||||
checkInheritedDescriptorsGroup(relevantDirectlyOverridden, descriptor, reportingStrategy);
|
||||
|
||||
if (kind == DELEGATION && overrideReportStrategyForDelegates != null) {
|
||||
checkOverridesForMember(descriptor, relevantDirectlyOverridden, overrideReportStrategyForDelegates);
|
||||
@@ -816,28 +816,25 @@ public class OverrideResolver {
|
||||
|
||||
private static void checkInheritedDescriptorsGroup(
|
||||
@NotNull Collection<CallableMemberDescriptor> inheritedDescriptors,
|
||||
@NotNull CallableMemberDescriptor mostSpecific,
|
||||
@NotNull CheckInheritedSignaturesReportStrategy reportingStrategy
|
||||
) {
|
||||
// FIXME This algorithm depends on transitiveness of sub-typing relation, which is broken in presence of flexible types.
|
||||
if (inheritedDescriptors.size() > 1) {
|
||||
Iterator<CallableMemberDescriptor> inheritedIterator = inheritedDescriptors.iterator();
|
||||
CallableMemberDescriptor mostSpecificInherited = inheritedIterator.next();
|
||||
while (inheritedIterator.hasNext()) {
|
||||
CallableMemberDescriptor overriddenDescriptor = inheritedIterator.next();
|
||||
if (OverridingUtil.isMoreSpecific(overriddenDescriptor, mostSpecificInherited)) {
|
||||
mostSpecificInherited = overriddenDescriptor;
|
||||
}
|
||||
}
|
||||
PropertyDescriptor mostSpecificProperty = mostSpecific instanceof PropertyDescriptor ? (PropertyDescriptor) mostSpecific : null;
|
||||
|
||||
for (CallableMemberDescriptor inheritedDescriptor : inheritedDescriptors) {
|
||||
if (!OverridingUtil.isMoreSpecific(mostSpecificInherited, inheritedDescriptor)) {
|
||||
if (inheritedDescriptor instanceof PropertyDescriptor) {
|
||||
reportingStrategy.propertyTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor);
|
||||
}
|
||||
else {
|
||||
reportingStrategy.returnTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor);
|
||||
if (mostSpecificProperty != null) {
|
||||
assert inheritedDescriptor instanceof PropertyDescriptor
|
||||
: inheritedDescriptor + " inherited from " + mostSpecificProperty + " is not a property";
|
||||
PropertyDescriptor inheritedPropertyDescriptor = (PropertyDescriptor) inheritedDescriptor;
|
||||
|
||||
if (!isPropertyTypeOkForOverride(inheritedPropertyDescriptor, mostSpecificProperty)) {
|
||||
reportingStrategy.propertyTypeMismatchOnInheritance(mostSpecific, inheritedDescriptor);
|
||||
}
|
||||
}
|
||||
else if (!isReturnTypeOkForOverride(inheritedDescriptor, mostSpecific)) {
|
||||
reportingStrategy.returnTypeMismatchOnInheritance(mostSpecific, inheritedDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -935,11 +932,15 @@ public class OverrideResolver {
|
||||
TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
|
||||
if (typeSubstitutor == null) return false;
|
||||
|
||||
if (!superDescriptor.isVar()) return true;
|
||||
|
||||
KotlinType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getType(), Variance.OUT_VARIANCE);
|
||||
assert substitutedSuperReturnType != null;
|
||||
return KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.getType(), substitutedSuperReturnType);
|
||||
|
||||
if (superDescriptor.isVar()) {
|
||||
return KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.getType(), substitutedSuperReturnType);
|
||||
}
|
||||
else {
|
||||
return KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.getType(), substitutedSuperReturnType);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOverrideForComponentFunction(@NotNull final CallableMemberDescriptor componentFunction) {
|
||||
|
||||
@@ -16,11 +16,11 @@ abstract class B<H>() : A<H> {
|
||||
override fun foo2() : <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Unit<!> {
|
||||
}
|
||||
|
||||
override val a : <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Double<!> = 1.toDouble()
|
||||
override val <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>a1<!> = 1.toDouble()
|
||||
override val a : <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>Double<!> = 1.toDouble()
|
||||
override val <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>a1<!> = 1.toDouble()
|
||||
|
||||
abstract override fun <X> g() : <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Int<!>
|
||||
abstract override fun <X> g1() : <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>List<X><!>
|
||||
|
||||
abstract override val g : <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Iterator<Int><!>
|
||||
abstract override val g : <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>Iterator<Int><!>
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ interface A {
|
||||
}
|
||||
|
||||
class AImpl: A {
|
||||
override val <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>prop<!> by Delegate()
|
||||
override val <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>prop<!> by Delegate()
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
|
||||
+4
-4
@@ -10,9 +10,9 @@ interface Three {
|
||||
public fun foo(): String
|
||||
}
|
||||
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test123<!>(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test132<!>(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, RETURN_TYPE_MISMATCH_ON_INHERITANCE!>class Test123<!>(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, RETURN_TYPE_MISMATCH_ON_INHERITANCE!>class Test132<!>(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test312<!>(val v1: One, val v2: Two, val v3: Three) : Three by v3, One by v1, Two by v2 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test321<!>(val v1: One, val v2: Two, val v3: Three) : Three by v3, Two by v2, One by v1 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test231<!>(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED!>class Test213<!>(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, RETURN_TYPE_MISMATCH_ON_INHERITANCE!>class Test231<!>(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { }
|
||||
<!MANY_IMPL_MEMBER_NOT_IMPLEMENTED, MANY_IMPL_MEMBER_NOT_IMPLEMENTED, RETURN_TYPE_MISMATCH_ON_INHERITANCE!>class Test213<!>(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { }
|
||||
+1
-1
@@ -60,7 +60,7 @@ public interface KDerived1b : J, K1 {
|
||||
|
||||
public interface KDerived2a : K2, J {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.String!
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.String?
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
Vendored
+9
-4
@@ -30,9 +30,14 @@ interface Test5 : ILNS, IMLS, J
|
||||
interface Test6 : ILNS, J, IMLS
|
||||
interface Test7 : J, ILNS, IMLS
|
||||
|
||||
// ILS and IMLNS are incompatible
|
||||
// Return types of ILS::foo and IMLNS::foo are incompatible themselves.
|
||||
// However, return type of J::foo is (Mutable)List<String!>!,
|
||||
// which is subtype of both List<String> and MutalbeList<String?>.
|
||||
// Thus, inheriting from J, IMLNS, and ILS is Ok,
|
||||
// but inheriting from IMLNS and ILS is not.
|
||||
|
||||
interface Test8 : J, IMLNS, ILS
|
||||
interface Test9 : IMLNS, J, ILS
|
||||
interface Test10 : IMLNS, ILS, J
|
||||
|
||||
<!RETURN_TYPE_MISMATCH_ON_INHERITANCE!>interface Test8<!> : J, IMLNS, ILS
|
||||
<!RETURN_TYPE_MISMATCH_ON_INHERITANCE!>interface Test9<!> : IMLNS, J, ILS
|
||||
<!RETURN_TYPE_MISMATCH_ON_INHERITANCE!>interface Test10<!> : IMLNS, ILS, J
|
||||
<!RETURN_TYPE_MISMATCH_ON_INHERITANCE!>interface Test11<!> : IMLNS, ILS
|
||||
Vendored
+3
-3
@@ -46,7 +46,7 @@ public interface Test1 : ILNS, J {
|
||||
|
||||
public interface Test10 : IMLNS, ILS, J {
|
||||
public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList<kotlin.String?>
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.(Mutable)List<kotlin.String!>!
|
||||
public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -102,14 +102,14 @@ public interface Test7 : J, ILNS, IMLS {
|
||||
|
||||
public interface Test8 : J, IMLNS, ILS {
|
||||
public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList<kotlin.String?>
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.(Mutable)List<kotlin.String!>!
|
||||
public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test9 : IMLNS, J, ILS {
|
||||
public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList<kotlin.String?>
|
||||
public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.(Mutable)List<kotlin.String!>!
|
||||
public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// FILE: JFooWithUpperBound.java
|
||||
public interface JFooWithUpperBound<T extends IBase> {
|
||||
T foo();
|
||||
}
|
||||
|
||||
// FILE: JFooWithUpperBoundDerived.java
|
||||
public interface JFooWithUpperBoundDerived<T extends IBase> extends JFooWithUpperBound<T> {
|
||||
}
|
||||
|
||||
// FILE: JCFooWithUpperBound.java
|
||||
public class JCFooWithUpperBound<T extends IBase> {
|
||||
public T foo() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: JCFooWithUpperBoundDerived.java
|
||||
public class JCFooWithUpperBoundDerived<T extends IBase> extends JCFooWithUpperBound<T> {
|
||||
}
|
||||
|
||||
// FILE: K.kt
|
||||
interface IBase
|
||||
|
||||
interface IDerived : IBase
|
||||
|
||||
interface IFooWithUpperBound<T : IBase> {
|
||||
fun foo(): T
|
||||
}
|
||||
|
||||
interface IFooT<T> {
|
||||
fun foo(): T
|
||||
}
|
||||
|
||||
interface IFoo {
|
||||
fun foo(): IBase
|
||||
}
|
||||
|
||||
interface IFooDerived : IFoo {
|
||||
override fun foo(): IDerived
|
||||
}
|
||||
|
||||
interface IFooWithUpperBoundDerived<T : IBase> : IFooWithUpperBound<T>
|
||||
|
||||
interface Test1<T : IBase> : IFooWithUpperBound<T>, IFoo
|
||||
|
||||
interface Test2<T : IBase> : IFooT<T>, IFoo
|
||||
|
||||
interface Test3<T : IDerived> : IFooWithUpperBoundDerived<T>, IFooDerived
|
||||
|
||||
interface Test4<T : IBase> : JFooWithUpperBound<T>, IFoo
|
||||
|
||||
interface Test5<T : IDerived> : JFooWithUpperBoundDerived<T>, IFooDerived
|
||||
|
||||
class Test6<T : IBase> : JCFooWithUpperBound<T>(), IFoo
|
||||
|
||||
class Test7<T : IDerived> : JCFooWithUpperBoundDerived<T>(), IFooDerived
|
||||
Vendored
+132
@@ -0,0 +1,132 @@
|
||||
package
|
||||
|
||||
public /*synthesized*/ fun </*0*/ T : IBase!> JFooWithUpperBound(/*0*/ function: () -> T!): JFooWithUpperBound<T>
|
||||
public /*synthesized*/ fun </*0*/ T : IBase!> JFooWithUpperBoundDerived(/*0*/ function: () -> T!): JFooWithUpperBoundDerived<T>
|
||||
|
||||
public interface IBase {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IDerived : IBase {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IFoo {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): IBase
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IFooDerived : IFoo {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ fun foo(): IDerived
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IFooT</*0*/ T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): T
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IFooWithUpperBound</*0*/ T : IBase> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): T
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IFooWithUpperBoundDerived</*0*/ T : IBase> : IFooWithUpperBound<T> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): T
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class JCFooWithUpperBound</*0*/ T : IBase!> {
|
||||
public constructor JCFooWithUpperBound</*0*/ T : IBase!>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open fun foo(): T!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public open class JCFooWithUpperBoundDerived</*0*/ T : IBase!> : JCFooWithUpperBound<T!> {
|
||||
public constructor JCFooWithUpperBoundDerived</*0*/ T : IBase!>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface JFooWithUpperBound</*0*/ T : IBase!> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract fun foo(): T!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface JFooWithUpperBoundDerived</*0*/ T : IBase!> : JFooWithUpperBound<T!> {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test1</*0*/ T : IBase> : IFooWithUpperBound<T>, IFoo {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): T
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test2</*0*/ T : IBase> : IFooT<T>, IFoo {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): T
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test3</*0*/ T : IDerived> : IFooWithUpperBoundDerived<T>, IFooDerived {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): T
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test4</*0*/ T : IBase> : JFooWithUpperBound<T>, IFoo {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface Test5</*0*/ T : IDerived> : JFooWithUpperBoundDerived<T>, IFooDerived {
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*2*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test6</*0*/ T : IBase> : JCFooWithUpperBound<T>, IFoo {
|
||||
public constructor Test6</*0*/ T : IBase>()
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*2*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Test7</*0*/ T : IDerived> : JCFooWithUpperBoundDerived<T>, IFooDerived {
|
||||
public constructor Test7</*0*/ T : IDerived>()
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*2*/ /*fake_override*/ fun foo(): T!
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -11360,6 +11360,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericWithUpperBound.kt")
|
||||
public void testGenericWithUpperBound() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/genericWithUpperBound.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("returnTypeMismatch.kt")
|
||||
public void testReturnTypeMismatch() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/returnTypeMismatch.kt");
|
||||
|
||||
@@ -28,14 +28,12 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeCapabilitiesKt;
|
||||
import org.jetbrains.kotlin.types.TypeConstructor;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*;
|
||||
import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE;
|
||||
|
||||
public class OverridingUtil {
|
||||
|
||||
@@ -322,11 +320,10 @@ public class OverridingUtil {
|
||||
|
||||
public static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) {
|
||||
KotlinType aReturnType = a.getReturnType();
|
||||
assert aReturnType != null : "Return type is null for " + a;
|
||||
// Use upper bound for flexible type.
|
||||
aReturnType = TypeCapabilitiesKt.getSupertypeRepresentative(aReturnType);
|
||||
KotlinType bReturnType = b.getReturnType();
|
||||
assert bReturnType != null : "Return type is null for " + b;
|
||||
|
||||
assert aReturnType != null : "Return type of " + a + " is null";
|
||||
assert bReturnType != null : "Return type of " + b + " is null";
|
||||
|
||||
if (a instanceof SimpleFunctionDescriptor) {
|
||||
assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
|
||||
@@ -341,13 +338,9 @@ public class OverridingUtil {
|
||||
if (pa.isVar() && pb.isVar()) {
|
||||
return KotlinTypeChecker.DEFAULT.equalTypes(aReturnType, bReturnType);
|
||||
}
|
||||
else if (!pa.isVar() && pb.isVar()) {
|
||||
// val can't be more specific than var, regardless of return type.
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// both vals or var <? val
|
||||
return KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType);
|
||||
// both vals or var vs val: val can't be more specific then var
|
||||
return !(!pa.isVar() && pb.isVar()) && KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
|
||||
@@ -381,7 +374,12 @@ public class OverridingUtil {
|
||||
// Should be 'foo(s: String): String'.
|
||||
Modality modality = getMinimalModality(effectiveOverridden);
|
||||
Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
|
||||
CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
|
||||
CallableMemberDescriptor mostSpecific =
|
||||
OverridingUtilsKt.getOverriddenWithMostSpecificReturnTypeOrNull(KotlinTypeChecker.DEFAULT, effectiveOverridden);
|
||||
if (mostSpecific == null) {
|
||||
// Use some (possibly erroneous) inherited signature. Will be reported as an error later.
|
||||
mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
|
||||
}
|
||||
CallableMemberDescriptor fakeOverride =
|
||||
mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
|
||||
for (CallableMemberDescriptor descriptor : effectiveOverridden) {
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import java.util.*
|
||||
|
||||
@@ -41,3 +46,64 @@ fun <TDescriptor : CallableDescriptor> TDescriptor.findOriginalTopMostOverridden
|
||||
(it.original as TDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun CallableDescriptor.isVar(): Boolean =
|
||||
this is PropertyDescriptor && isVar
|
||||
|
||||
private fun CallableDescriptor.isVal(): Boolean =
|
||||
this is PropertyDescriptor && !isVar
|
||||
|
||||
private fun isMostSpecificByReturnTypeAndKind(
|
||||
type: KotlinType,
|
||||
returnTypeOwner: CallableDescriptor,
|
||||
descriptors: Collection<CallableDescriptor>,
|
||||
typeChecker: KotlinTypeChecker
|
||||
): Boolean =
|
||||
descriptors.all {
|
||||
otherDescriptor ->
|
||||
otherDescriptor == returnTypeOwner ||
|
||||
(!(returnTypeOwner.isVal() && otherDescriptor.isVar()) &&
|
||||
otherDescriptor.returnType?.let { typeChecker.isSubtypeOf(type, it) } ?: true)
|
||||
}
|
||||
|
||||
|
||||
fun <TDescriptor : CallableDescriptor> getOverriddenWithMostSpecificReturnTypeOrNull(
|
||||
typeChecker: KotlinTypeChecker,
|
||||
descriptors: Collection<TDescriptor>
|
||||
): TDescriptor? {
|
||||
val candidates = arrayListOf<TDescriptor>()
|
||||
|
||||
// Need this to avoid recursion on lazy types.
|
||||
if (descriptors.isEmpty()) {
|
||||
return null
|
||||
} else if (descriptors.size == 1) {
|
||||
return descriptors.first()
|
||||
}
|
||||
|
||||
for (descriptor in descriptors) {
|
||||
val returnType = descriptor.returnType ?: continue
|
||||
|
||||
if (isMostSpecificByReturnTypeAndKind(returnType, descriptor, descriptors, typeChecker)) {
|
||||
candidates.add(descriptor)
|
||||
}
|
||||
else if (!TypeUtils.canHaveSubtypes(typeChecker, returnType)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
var withNonErrorReturnType: TDescriptor? = null
|
||||
var withNonFlexibleReturnType: TDescriptor? = null
|
||||
for (candidate in candidates) {
|
||||
val returnType = candidate.returnType ?: continue
|
||||
withNonErrorReturnType = candidate
|
||||
if (!returnType.isFlexible()) {
|
||||
withNonFlexibleReturnType = candidate
|
||||
}
|
||||
}
|
||||
return withNonFlexibleReturnType ?: withNonErrorReturnType
|
||||
}
|
||||
Reference in New Issue
Block a user