diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt index b501ca53a81..8aa9b75e5f6 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized +import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled +import org.jetbrains.kotlin.resolve.descriptorUtil.module fun generateBridgesForFunctionDescriptor( descriptor: FunctionDescriptor, @@ -128,6 +130,6 @@ fun firstSuperMethodFromKotlin( ): CallableMemberDescriptor? { return descriptor.overriddenDescriptors.firstOrNull { overridden -> overridden.modality != Modality.ABSTRACT && - (overridden == implementation || OverridingUtil.overrides(overridden, implementation)) + (overridden == implementation || OverridingUtil.overrides(overridden, implementation, overridden.module.isTypeRefinementEnabled())) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt index 1ff2483111f..59e14cc48a8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt @@ -26,6 +26,8 @@ import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE +import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.lazy.DelegationFilter import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.isDynamic @@ -172,7 +174,13 @@ class DelegationResolver private constructor( // this is the actual member of delegateExpressionType that we are delegating to (scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) + scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES)) - .firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) } + .firstOrNull { + it == overriddenDescriptor || OverridingUtil.overrides( + it, + overriddenDescriptor, + it.module.isTypeRefinementEnabled() + ) + } } actualDelegates.firstOrNull() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt index b0b625c7bf1..747e7c0e54c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt @@ -61,7 +61,10 @@ interface IdentifierInfo { get() = kind == STABLE_VALUE override fun equals(other: Any?) = - other is Variable && DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(variable, other.variable) + other is Variable && + DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent( + variable, other.variable, allowCopiesFromTheSameDeclaration = true + ) override fun hashCode() = variable.name.hashCode() * 31 + variable.containingDeclaration.original.hashCode() diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt index 98923a99ab2..12d95bd8dd8 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode +import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled import org.jetbrains.kotlin.resolve.descriptorUtil.varargParameterPosition import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils @@ -44,6 +45,8 @@ open class OverloadingConflictResolver( private val hasSAMConversion: ((C) -> Boolean)? ) { + private val isTypeRefinementEnabled by lazy { module.isTypeRefinementEnabled() } + private val resolvedCallHashingStrategy = object : TObjectHashingStrategy { override fun equals(call1: C?, call2: C?): Boolean = if (call1 != null && call2 != null) @@ -72,7 +75,10 @@ open class OverloadingConflictResolver( } val noEquivalentCalls = filterOutEquivalentCalls(fixedCandidates) - val noOverrides = OverridingUtil.filterOverrides(noEquivalentCalls) { a, b -> + val noOverrides = OverridingUtil.filterOverrides( + noEquivalentCalls, + isTypeRefinementEnabled + ) { a, b -> val aDescriptor = a.resultingDescriptor val bDescriptor = b.resultingDescriptor // Here we'd like to handle situation when we have two synthetic descriptors as in syntheticSAMExtensions.kt @@ -121,7 +127,13 @@ open class OverloadingConflictResolver( val me = meD.resultingDescriptor val other = otherD.resultingDescriptor val ignoreReturnType = isFromSources(me) != isFromSources(other) - if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(me, other, ignoreReturnType)) { + if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent( + me, + other, + isTypeRefinementEnabled, + ignoreReturnType + ) + ) { continue@outerLoop } } diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java index ace832312b1..360429ed747 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java @@ -329,7 +329,7 @@ public abstract class ExpectedResolveData { } private static void assertDescriptorsEqual(String message, DeclarationDescriptor expected, DeclarationDescriptor actual) { - if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(expected, actual)) { + if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(expected, actual, true)) { return; } String formatted = ""; diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt index 4c6ecc86ebe..7e9080649e5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt @@ -21,16 +21,20 @@ import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo object DescriptorEquivalenceForOverrides { - fun areEquivalent(a: DeclarationDescriptor?, b: DeclarationDescriptor?): Boolean { + fun areEquivalent( + a: DeclarationDescriptor?, + b: DeclarationDescriptor?, + allowCopiesFromTheSameDeclaration: Boolean + ): Boolean { return when { a is ClassDescriptor && b is ClassDescriptor -> areClassesEquivalent(a, b) a is TypeParameterDescriptor && - b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b) + b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b, allowCopiesFromTheSameDeclaration) a is CallableDescriptor && - b is CallableDescriptor -> areCallableDescriptorsEquivalent(a, b) + b is CallableDescriptor -> areCallableDescriptorsEquivalent(a, b, allowCopiesFromTheSameDeclaration) a is PackageFragmentDescriptor && b is PackageFragmentDescriptor -> (a).fqName == (b).fqName @@ -47,12 +51,13 @@ object DescriptorEquivalenceForOverrides { private fun areTypeParametersEquivalent( a: TypeParameterDescriptor, b: TypeParameterDescriptor, + allowCopiesFromTheSameDeclaration: Boolean, equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean = { _, _ -> false } ): Boolean { if (a == b) return true if (a.containingDeclaration == b.containingDeclaration) return false - if (!ownersEquivalent(a, b, equivalentCallables)) return false + if (!ownersEquivalent(a, b, equivalentCallables, allowCopiesFromTheSameDeclaration)) return false return a.index == b.index // We ignore type parameter names } @@ -66,11 +71,13 @@ object DescriptorEquivalenceForOverrides { fun areCallableDescriptorsEquivalent( a: CallableDescriptor, b: CallableDescriptor, + allowCopiesFromTheSameDeclaration: Boolean, ignoreReturnType: Boolean = false ): Boolean { if (a == b) return true if (a.name != b.name) return false if (a.containingDeclaration == b.containingDeclaration) { + if (!allowCopiesFromTheSameDeclaration) return false if (a.singleSource() != b.singleSource()) return false if (a is MemberDescriptor && b is MemberDescriptor && a.isExpect != b.isExpect) return false } @@ -78,7 +85,7 @@ object DescriptorEquivalenceForOverrides { // Distinct locals are not equivalent if (DescriptorUtils.isLocal(a) || DescriptorUtils.isLocal(b)) return false - if (!ownersEquivalent(a, b, { _, _ -> false })) return false + if (!ownersEquivalent(a, b, { _, _ -> false }, allowCopiesFromTheSameDeclaration)) return false val overridingUtil = OverridingUtil.createWithEqualityAxioms eq@{ c1, c2 -> if (c1 == c2) return@eq true @@ -88,7 +95,7 @@ object DescriptorEquivalenceForOverrides { if (d1 !is TypeParameterDescriptor || d2 !is TypeParameterDescriptor) return@eq false - areTypeParametersEquivalent(d1, d2, { x, y -> x == a && y == b }) + areTypeParametersEquivalent(d1, d2, allowCopiesFromTheSameDeclaration) { x, y -> x == a && y == b } } return overridingUtil.isOverridableBy(a, b, null, !ignoreReturnType).result == OverrideCompatibilityInfo.Result.OVERRIDABLE @@ -99,7 +106,8 @@ object DescriptorEquivalenceForOverrides { private fun ownersEquivalent( a: DeclarationDescriptor, b: DeclarationDescriptor, - equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean + equivalentCallables: (DeclarationDescriptor?, DeclarationDescriptor?) -> Boolean, + allowCopiesFromTheSameDeclaration: Boolean ): Boolean { val aOwner = a.containingDeclaration val bOwner = b.containingDeclaration @@ -109,7 +117,7 @@ object DescriptorEquivalenceForOverrides { return if (aOwner is CallableMemberDescriptor || bOwner is CallableMemberDescriptor) { equivalentCallables(aOwner, bOwner) } else { - areEquivalent(aOwner, bOwner) + areEquivalent(aOwner, bOwner, allowCopiesFromTheSameDeclaration) } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index a3b69c50530..224f42c49b3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -446,4 +446,7 @@ fun DeclarationDescriptor.isPrimaryConstructorOfInlineClass(): Boolean = this is ConstructorDescriptor && this.isPrimary && this.constructedClass.isInline @TypeRefinement -fun ModuleDescriptor.getKotlinTypeRefiner(): KotlinTypeRefiner = getCapability(REFINER_CAPABILITY)?.value ?: KotlinTypeRefiner.Default \ No newline at end of file +fun ModuleDescriptor.getKotlinTypeRefiner(): KotlinTypeRefiner = getCapability(REFINER_CAPABILITY)?.value ?: KotlinTypeRefiner.Default + +@UseExperimental(TypeRefinement::class) +fun ModuleDescriptor.isTypeRefinementEnabled(): Boolean = getCapability(REFINER_CAPABILITY)?.value != null diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index d6ac2aebdd8..d0e87ec94bd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl; 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.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.types.FlexibleTypesKt; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinTypeKt; @@ -92,7 +93,11 @@ public class OverridingUtil { */ @NotNull public static Set filterOutOverridden(@NotNull Set candidateSet) { - return filterOverrides(candidateSet, new Function2>() { + boolean allowDescriptorCopies = !candidateSet.isEmpty() && + DescriptorUtilsKt + .isTypeRefinementEnabled(DescriptorUtilsKt.getModule(candidateSet.iterator().next())); + + return filterOverrides(candidateSet, allowDescriptorCopies, new Function2>() { @Override public Pair invoke(D a, D b) { return new Pair(a, b); @@ -103,6 +108,7 @@ public class OverridingUtil { @NotNull public static Set filterOverrides( @NotNull Set candidateSet, + boolean allowDescriptorCopies, @NotNull Function2> transformFirst ) { if (candidateSet.size() <= 1) return candidateSet; @@ -115,10 +121,10 @@ public class OverridingUtil { Pair meAndOther = transformFirst.invoke(meD, otherD); CallableDescriptor me = meAndOther.component1(); CallableDescriptor other = meAndOther.component2(); - if (overrides(me, other)) { + if (overrides(me, other, allowDescriptorCopies)) { iterator.remove(); } - else if (overrides(other, me)) { + else if (overrides(other, me, allowDescriptorCopies)) { continue outerLoop; } } @@ -133,7 +139,9 @@ public class OverridingUtil { /** * @return whether f overrides g */ - public static boolean overrides(@NotNull D f, @NotNull D g) { + public static boolean overrides( + @NotNull D f, @NotNull D g, boolean allowDeclarationCopies + ) { // In a multi-module project different "copies" of the same class may be present in different libraries, // that's why we use structural equivalence for members (DescriptorEquivalenceForOverrides). @@ -142,11 +150,11 @@ public class OverridingUtil { // we'll be getting sets of members that do not override each other, but are structurally equivalent. // As other code relies on no equal descriptors passed here, we guard against f == g, but this may not be necessary // Note that this is needed for the usage of this function in the IDE code - if (!f.equals(g) && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(f.getOriginal(), g.getOriginal())) return true; + if (!f.equals(g) && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(f.getOriginal(), g.getOriginal(), allowDeclarationCopies)) return true; CallableDescriptor originalG = g.getOriginal(); for (D overriddenFunction : DescriptorUtils.getAllOverriddenDescriptors(f)) { - if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(originalG, overriddenFunction)) return true; + if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(originalG, overriddenFunction, allowDeclarationCopies)) return true; } return false; } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/KotlinPsiUnifier.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/KotlinPsiUnifier.kt index 455d146dc63..21ce4a65473 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/KotlinPsiUnifier.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/KotlinPsiUnifier.kt @@ -124,7 +124,7 @@ class KotlinPsiUnifier( } private fun matchDescriptors(d1: DeclarationDescriptor?, d2: DeclarationDescriptor?): Boolean { - if (DescriptorEquivalenceForOverrides.areEquivalent(d1, d2)) return true + if (DescriptorEquivalenceForOverrides.areEquivalent(d1, d2, allowCopiesFromTheSameDeclaration = true)) return true if (d2 in declarationPatternsToTargets[d1] || d1 in declarationPatternsToTargets[d2]) return true if (d1 == null || d2 == null) return false diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt index 3321fe3a124..e6304be539f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt @@ -46,6 +46,8 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.descriptorUtil.isTypeRefinementEnabled +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode val KtDeclaration.descriptor: DeclarationDescriptor? @@ -265,7 +267,11 @@ fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boole when (it) { is KtDeclaration -> { val usageDescriptor = toDescriptor(it) - usageDescriptor != null && OverridingUtil.overrides(usageDescriptor, targetDescriptor) + usageDescriptor != null && OverridingUtil.overrides( + usageDescriptor, + targetDescriptor, + usageDescriptor.module.isTypeRefinementEnabled() + ) } is PsiMethod -> { declaration.toLightMethods().any { superMethod -> MethodSignatureUtil.isSuperMethod(superMethod, it) } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt index 7c2a0897a8f..59bdf2c3fb7 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsNameClashChecker.kt @@ -33,8 +33,6 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty import org.jetbrains.kotlin.resolve.scopes.MemberScope -import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner -import org.jetbrains.kotlin.types.refinement.TypeRefinement class JsNameClashChecker( private val nameSuggestion: NameSuggestion, @@ -125,7 +123,9 @@ class JsNameClashChecker( } else { // If refinement is enabled, we can get duplicate descriptors for one and the same members (as refinement re-creates // descriptors), so, in this case, we have to compare descriptors structurally - DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(existing, overrideDescriptor) + DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent( + existing, overrideDescriptor, allowCopiesFromTheSameDeclaration = true + ) } }