[PL] Make call an exception in case of several inherited implementations
^KT-57701
This commit is contained in:
committed by
Space Team
parent
fde8909e6f
commit
ee1608ec99
+46
-7
@@ -6,23 +6,22 @@
|
||||
package org.jetbrains.kotlin.backend.common.linkage.partial
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrOverridableMember
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.linkage.partial.IrUnimplementedOverridesStrategy
|
||||
import org.jetbrains.kotlin.ir.linkage.partial.PartiallyLinkedDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.collectRealOverrides
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
|
||||
internal class ImplementAsErrorThrowingStubs(
|
||||
private val partialLinkageSupport: PartialLinkageSupportForLinker
|
||||
) : IrUnimplementedOverridesStrategy {
|
||||
override fun <T : IrOverridableMember> computeCustomization(overridableMember: T, parent: IrClass) =
|
||||
override fun <S : IrSymbol, T : IrOverridableDeclaration<S>> computeCustomization(overridableMember: T, parent: IrClass) =
|
||||
if (overridableMember.isAbstract
|
||||
&& parent.isConcrete
|
||||
&& !parent.isExternal
|
||||
&& parent.isEligibleForPartialLinkage()
|
||||
&& !parent.delegatesToNothing
|
||||
&& !partialLinkageSupport.shouldBeSkipped(parent)
|
||||
) {
|
||||
IrUnimplementedOverridesStrategy.Customization(
|
||||
origin = PartiallyLinkedDeclarationOrigin.UNIMPLEMENTED_ABSTRACT_CALLABLE_MEMBER,
|
||||
@@ -30,6 +29,46 @@ internal class ImplementAsErrorThrowingStubs(
|
||||
)
|
||||
} else IrUnimplementedOverridesStrategy.Customization.NO
|
||||
|
||||
override fun <S : IrSymbol, T : IrOverridableDeclaration<S>> postProcessGeneratedFakeOverride(overridableMember: T, parent: IrClass) {
|
||||
if (parent.isEligibleForPartialLinkage() && overridableMember.isAmbiguous()) {
|
||||
fun IrOverridableDeclaration<*>.mark() {
|
||||
if (isFakeOverride) {
|
||||
origin = PartiallyLinkedDeclarationOrigin.AMBIGUOUS_NON_OVERRIDDEN_CALLABLE_MEMBER
|
||||
isFakeOverride = false
|
||||
}
|
||||
}
|
||||
overridableMember.mark()
|
||||
if (overridableMember is IrProperty) {
|
||||
overridableMember.getter?.mark()
|
||||
overridableMember.setter?.mark()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns if fake override has unique implementation in super classes to be chosen on call
|
||||
*
|
||||
* Candidates is a list of real functions we override, which are not overridden themselves
|
||||
* by any other function in the list.
|
||||
*
|
||||
* If there is a **real** super-class function in the list, it must be unique.
|
||||
* In that case it is preferred over functions coming from default implementation in interfaces.
|
||||
*
|
||||
* If there is no such function, but there are several interface function - it is an incompatible change.
|
||||
*
|
||||
* This is done to mimic jvm behaviour.
|
||||
*/
|
||||
private fun <S : IrSymbol, T : IrOverridableDeclaration<S>> T.isAmbiguous(): Boolean {
|
||||
val candidates = collectRealOverrides().filter { !it.isAbstract }
|
||||
if (candidates.any { ((it.symbol.owner as IrDeclaration).parent as? IrClass)?.isInterface == false }) {
|
||||
return false
|
||||
}
|
||||
return candidates.size > 1
|
||||
}
|
||||
|
||||
private fun IrClass.isEligibleForPartialLinkage() = !isExternal && !partialLinkageSupport.shouldBeSkipped(this)
|
||||
|
||||
|
||||
private val IrOverridableMember.isAbstract: Boolean
|
||||
get() = modality == Modality.ABSTRACT
|
||||
|
||||
|
||||
+9
@@ -79,6 +79,8 @@ internal fun PartialLinkageCase.renderLinkageError(): String = buildString {
|
||||
|
||||
is UnimplementedAbstractCallable -> unimplementedAbstractCallable(callable)
|
||||
is UnusableAnnotation -> unusableAnnotation(annotationConstructorSymbol, holderDeclarationSymbol)
|
||||
|
||||
is AmbiguousNonOverriddenCallable -> ambiguousNonOverriddenCallable(callable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,6 +590,13 @@ private fun Appendable.unusableAnnotation(annotationConstructorSymbol: IrConstru
|
||||
append("Unusable annotation ").declarationName(annotationConstructorSymbol)
|
||||
.append(" has been removed from ").declarationKindName(holderDeclarationSymbol, capitalized = false)
|
||||
|
||||
private fun Appendable.ambiguousNonOverriddenCallable(callable: IrOverridableDeclaration<*>): Appendable =
|
||||
declarationKindName(callable.symbol, capitalized = true)
|
||||
.append(" in ")
|
||||
.declarationKindName(callable.parentAsClass.symbol, capitalized = false)
|
||||
.append(" inherits more than one default implementation")
|
||||
|
||||
|
||||
private fun Appendable.appendCapitalized(text: String, capitalized: Boolean): Appendable {
|
||||
if (capitalized && text.isNotEmpty()) {
|
||||
val firstChar = text[0]
|
||||
|
||||
+1
@@ -265,6 +265,7 @@ internal class PartiallyLinkedIrTreePatcher(
|
||||
// Compute the linkage case.
|
||||
val partialLinkageCase = when (declaration.origin) {
|
||||
PartiallyLinkedDeclarationOrigin.UNIMPLEMENTED_ABSTRACT_CALLABLE_MEMBER -> UnimplementedAbstractCallable(declaration)
|
||||
PartiallyLinkedDeclarationOrigin.AMBIGUOUS_NON_OVERRIDDEN_CALLABLE_MEMBER -> AmbiguousNonOverriddenCallable(declaration)
|
||||
PartiallyLinkedDeclarationOrigin.MISSING_DECLARATION -> MissingDeclaration(declaration.symbol)
|
||||
else -> unusableClassifierInSignature?.let { DeclarationWithUnusableClassifier(declaration.symbol, it) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user