From ab9ff786d777e72ac73f6709f42b5bd379bef5d4 Mon Sep 17 00:00:00 2001 From: Dmitry Savvinov Date: Thu, 25 Jul 2019 18:46:26 +0300 Subject: [PATCH] [Invariant Fix] Use structural descriptor equivalence in JsNamesClashChecker It's needed for situation when we have JS module with expect declaration, so we refine member scope for that expect declaration and try to compare to function descriptors (e.g. of `equals` function) from different class descriptors (expect and actual) and report diagnostic about name clash. So, since we can earn descriptors from type refinement, they can be not identical but still equals, so with should use structural equality to comparing them --- .../resolve/diagnostics/JsNameClashChecker.kt | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) 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 9fee3a31cc8..7c2a0897a8f 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 @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.js.resolve.diagnostics +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.config.isTypeRefinementEnabled import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors @@ -24,14 +26,20 @@ import org.jetbrains.kotlin.js.naming.SuggestedName import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +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) : DeclarationChecker { +class JsNameClashChecker( + private val nameSuggestion: NameSuggestion, + private val languageVersionSettings: LanguageVersionSettings +) : DeclarationChecker { companion object { private val COMMON_DIAGNOSTICS = setOf( Errors.REDECLARATION, @@ -87,7 +95,12 @@ class JsNameClashChecker(private val nameSuggestion: NameSuggestion) : Declarati val scope = getScope(overrideFqn.scope) val name = overrideFqn.names.last() val existing = scope[name] as? CallableMemberDescriptor - if (existing != null && existing != overrideFqn.descriptor && !isFakeOverridingNative(existing)) { + val overrideDescriptor = overrideFqn.descriptor as? CallableMemberDescriptor + if (existing != null && + overrideDescriptor != null && + !areDescriptorsEquivalent(existing, overrideDescriptor) && + !isFakeOverridingNative(existing) + ) { diagnosticHolder.report(ErrorsJs.JS_FAKE_NAME_CLASH.on(declaration, name, override, existing)) break } @@ -102,6 +115,20 @@ class JsNameClashChecker(private val nameSuggestion: NameSuggestion) : Declarati } } + private fun areDescriptorsEquivalent( + existing: CallableMemberDescriptor, + overrideDescriptor: CallableMemberDescriptor + ): Boolean { + return if (!languageVersionSettings.isTypeRefinementEnabled) { + // Fast-path + existing == overrideDescriptor + } 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) + } + } + private fun NameSuggestion.suggestAllPossibleNames(descriptor: DeclarationDescriptor): Collection = if (descriptor is CallableMemberDescriptor) { val primary = suggest(descriptor)