[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
This commit is contained in:
+30
-3
@@ -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<SuggestedName> =
|
||||
if (descriptor is CallableMemberDescriptor) {
|
||||
val primary = suggest(descriptor)
|
||||
|
||||
Reference in New Issue
Block a user