From 02311538d6216104af35c1bfaca824f91c74da64 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 10 Dec 2015 13:30:25 +0300 Subject: [PATCH] Refactor createAntBindFakeOverride. Drop unneeded helper functions from overridingUtils.kt --- .../kotlin/resolve/OverridingUtil.java | 59 ++++++++++++++---- .../kotlin/resolve/overridingUtils.kt | 61 ------------------- 2 files changed, 47 insertions(+), 73 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 1cd19ee5523..532d50a1894 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl; 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.FlexibleTypesKt; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.TypeConstructor; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; @@ -358,14 +359,53 @@ public class OverridingUtil { throw new IllegalArgumentException("Unexpected callable: " + a.getClass()); } - private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection overridables) { - CallableMemberDescriptor result = null; - for (CallableMemberDescriptor overridable : overridables) { - if (result == null || isMoreSpecific(overridable, result)) { - result = overridable; + private static boolean isMoreSpecificThenAllOf(@NotNull CallableMemberDescriptor candidate, @NotNull Collection descriptors) { + // NB subtyping relation in Kotlin is not transitive in presence of flexible types: + // String? <: String! <: String, but not String? <: String + for (CallableMemberDescriptor descriptor : descriptors) { + if (!isMoreSpecific(candidate, descriptor)) { + return false; } } - return result; + return true; + } + + private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection overridables) { + assert !overridables.isEmpty() : "Should have at least one overridable descriptor"; + + if (overridables.size() == 1) { + return CollectionsKt.first(overridables); + } + + Collection candidates = new ArrayList(2); + CallableMemberDescriptor transitivelyMostSpecific = null; + for (CallableMemberDescriptor overridable : overridables) { + if (isMoreSpecificThenAllOf(overridable, overridables)) { + candidates.add(overridable); + } + if (transitivelyMostSpecific == null || isMoreSpecific(overridable, transitivelyMostSpecific)) { + transitivelyMostSpecific = overridable; + } + } + + if (candidates.isEmpty()) { + return transitivelyMostSpecific; + } + else if (candidates.size() == 1) { + return CollectionsKt.first(candidates); + } + + CallableMemberDescriptor lastNonFlexible = null; + for (CallableMemberDescriptor candidate : candidates) { + if (!FlexibleTypesKt.isFlexible(candidate.getReturnType())) { + lastNonFlexible = candidate; + } + } + if (lastNonFlexible != null) { + return lastNonFlexible; + } + + return CollectionsKt.last(candidates); } private static void createAndBindFakeOverride( @@ -386,12 +426,7 @@ public class OverridingUtil { // Should be 'foo(s: String): String'. Modality modality = getMinimalModality(effectiveOverridden); Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED; - 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 mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden); CallableMemberDescriptor fakeOverride = mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false); for (CallableMemberDescriptor descriptor : effectiveOverridden) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt index b92a057a4f1..12230c57842 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/overridingUtils.kt @@ -46,64 +46,3 @@ fun 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, - typeChecker: KotlinTypeChecker -): Boolean = - descriptors.all { - otherDescriptor -> - otherDescriptor == returnTypeOwner || - (!(returnTypeOwner.isVal() && otherDescriptor.isVar()) && - otherDescriptor.returnType?.let { typeChecker.isSubtypeOf(type, it) } ?: true) - } - - -fun getOverriddenWithMostSpecificReturnTypeOrNull( - typeChecker: KotlinTypeChecker, - descriptors: Collection -): TDescriptor? { - val candidates = arrayListOf() - - // 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 -} \ No newline at end of file