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:
Dmitry Petrov
2015-12-07 17:16:14 +03:00
parent 594039ac42
commit 94bea54db3
12 changed files with 312 additions and 48 deletions
@@ -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><!>
}
@@ -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() {
@@ -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 { }
@@ -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
}
@@ -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
@@ -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
}
@@ -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
@@ -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
}