[IR] Fix missing AMBIGUOUS_ACTUALS

^KT-59938 Fixed
Review: https://jetbrains.team/p/kt/reviews/13760

After this patch:

    > The /compiler/testData/diagnostics/tests/multiplatform/topLevelFun/conflictingImplDeclarations.kt test:

    Fixed

    > The /compiler/testData/diagnostics/tests/multiplatform/headerClass/expectDeclarationWithWeakIncompatibilities.kt test:

    Declarations are in the same module. `PACKAGE_OR_CLASSIFIER_REDECLARATION` is reported anyway

    > The /compiler/testData/diagnostics/tests/multiplatform/java/varPropertyAgainstJavaGetterAndNonFinalField.kt test:

    Expect-actual matcher doesn't match fields in K2 https://youtrack.jetbrains.com/issue/KT-63667 => green code

    > The /compiler/testData/diagnostics/tests/multiplatform/java/propertyAgainstJavaPrivateFieldAndPublicMethod.kt test:

    Expect-actual matcher doesn't match fields in K2 https://youtrack.jetbrains.com/issue/KT-63667 => green code

    > The /compiler/testData/diagnostics/tests/multiplatform/java/implicitJavaActualization_multipleActuals.kt test:

    K2 doesn't have implicit Java actualization. And PACKAGE_OR_CLASSIFIER_REDECLARATION is reported anyway

    > The /compiler/testData/diagnostics/tests/multiplatform/java/propertyAgainstJavaPublicFieldAndPublicGetter.kt test:

    Expect-actual matcher doesn't match fields in K2 https://youtrack.jetbrains.com/issue/KT-63667 => green code

    > The /compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.kt test:

    Context receivers are not supported in expect-actual matcher. https://youtrack.jetbrains.com/issue/KT-61447
    And K2 reports another error right now anyway
This commit is contained in:
Nikita Bobko
2023-12-05 15:10:32 +01:00
committed by Space Team
parent e6860054ea
commit 013b5e3780
25 changed files with 129 additions and 24 deletions
@@ -309,12 +309,12 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
override fun onMatchedClasses(expectClassSymbol: IrClassSymbol, actualClassSymbol: IrClassSymbol) {
destination[expectClassSymbol] = actualClassSymbol
expectActualTracker?.reportWithCurrentFile(actualClassSymbol)
recordActualForExpectDeclaration(expectClassSymbol, actualClassSymbol, destination)
recordActualForExpectDeclaration(expectClassSymbol, actualClassSymbol, destination, diagnosticsReporter)
}
override fun onMatchedCallables(expectSymbol: IrSymbol, actualSymbol: IrSymbol) {
expectActualTracker?.reportWithCurrentFile(actualSymbol)
recordActualForExpectDeclaration(expectSymbol, actualSymbol, destination)
recordActualForExpectDeclaration(expectSymbol, actualSymbol, destination, diagnosticsReporter)
}
override fun onIncompatibleMembersFromClassScope(
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isExpect
@@ -25,7 +25,10 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
* This Actualizer processes expect overridable declarations in non-expect classes and replaces them with the associated actual overridable
* declarations overriding the actual base class members.The newly created actual fake overrides are stored in expectActualMap.
*/
internal class FakeOverridesActualizer(private val expectActualMap: MutableMap<IrSymbol, IrSymbol>) : IrElementVisitorVoid {
internal class FakeOverridesActualizer(
private val expectActualMap: MutableMap<IrSymbol, IrSymbol>,
private val diagnosticReporter: IrDiagnosticReporter
) : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) {
if (!declaration.isExpect) {
actualizeFakeOverrides(declaration)
@@ -47,7 +50,7 @@ internal class FakeOverridesActualizer(private val expectActualMap: MutableMap<I
val actualizedOverrides = overriddenSymbols.map { (it.owner as IrDeclaration).actualize() }
val actualFakeOverride = createFakeOverrideMember(actualizedOverrides, parent as IrClass)
recordActualForExpectDeclaration(this.symbol, actualFakeOverride.symbol, expectActualMap)
recordActualForExpectDeclaration(this.symbol, actualFakeOverride.symbol, expectActualMap, diagnosticReporter)
return actualFakeOverride
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibil
internal object IrActualizationErrors {
val NO_ACTUAL_FOR_EXPECT by error2<PsiElement, String, ModuleDescriptor>()
val AMBIGUOUS_ACTUALS by error2<PsiElement, String, ModuleDescriptor>()
val EXPECT_ACTUAL_MISMATCH by error3<PsiElement, String, String, ExpectActualMatchingCompatibility.Mismatch>()
val EXPECT_ACTUAL_INCOMPATIBILITY by error3<PsiElement, String, String, ExpectActualCheckingCompatibility.Incompatible<*>>()
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning3<PsiElement, IrSymbol, IrSymbol, ExpectActualAnnotationsIncompatibilityType<IrConstructorCall>>()
@@ -34,6 +35,12 @@ internal object IrActualizationErrors {
internal object KtDefaultIrActualizationErrorMessages : BaseDiagnosticRendererFactory() {
override val MAP = KtDiagnosticFactoryToRendererMap("KT").also { map ->
map.put(
IrActualizationErrors.AMBIGUOUS_ACTUALS,
"{0} has several compatible actual declarations in modules {1}",
CommonRenderers.STRING,
IrActualizationDiagnosticRenderers.MODULE_WITH_PLATFORM,
)
map.put(
IrActualizationErrors.NO_ACTUAL_FOR_EXPECT,
"Expected {0} has no actual declaration in module {1}",
@@ -83,7 +83,7 @@ class IrActualizer(
if (!useIrFakeOverrideBuilder) {
// 2. Actualize expect fake overrides in non-expect classes inside common or multi-platform module.
// It's probably important to run FakeOverridesActualizer before ActualFakeOverridesAdder
FakeOverridesActualizer(expectActualMap).apply { dependentFragments.forEach { visitModuleFragment(it) } }
FakeOverridesActualizer(expectActualMap, ktDiagnosticReporter).apply { dependentFragments.forEach { visitModuleFragment(it) } }
// 3. Add fake overrides to non-expect classes inside common or multi-platform module,
// taken from these non-expect classes actualized super classes.
@@ -55,18 +55,13 @@ internal fun recordActualForExpectDeclaration(
expectSymbol: IrSymbol,
actualSymbol: IrSymbol,
destination: MutableMap<IrSymbol, IrSymbol>,
diagnosticsReporter: IrDiagnosticReporter,
) {
val expectDeclaration = expectSymbol.owner as IrDeclarationBase
val actualDeclaration = actualSymbol.owner as IrDeclaration
val registeredActual = destination.put(expectSymbol, actualSymbol)
require(registeredActual == null || registeredActual == actualSymbol) {
"""
Expect symbol already has registered mapping
Expect declaration: ${expectDeclaration.render()}
Actual declaration: ${actualDeclaration.render()}
Already registered: ${registeredActual!!.owner.render()}
""".trimIndent()
if (registeredActual != null && registeredActual != actualSymbol) {
diagnosticsReporter.reportAmbiguousActuals(expectDeclaration)
}
if (expectDeclaration is IrTypeParametersContainer) {
recordTypeParametersMapping(destination, expectDeclaration, actualDeclaration as IrTypeParametersContainer)
@@ -107,6 +102,15 @@ internal fun IrDiagnosticReporter.reportMissingActual(irDeclaration: IrDeclarati
)
}
@OptIn(ObsoleteDescriptorBasedAPI::class)
internal fun IrDiagnosticReporter.reportAmbiguousActuals(expectSymbol: IrDeclaration) {
at(expectSymbol).report(
IrActualizationErrors.AMBIGUOUS_ACTUALS,
(expectSymbol as? IrDeclarationWithName)?.name?.asString().orEmpty(),
expectSymbol.module
)
}
internal fun IrDiagnosticReporter.reportExpectActualIncompatibility(
expectSymbol: IrSymbol,
actualSymbol: IrSymbol,