[IR] Support ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE in K2

It's implemented as IR checker because in K2 constant expressions are
evaluated on backend. FIR diagnostic removed because isn't needed.

"annotationViaActualTypeAlias" test has no `// FIR_IDENTICAL` because
diagnostic reported on entire typealias declaration instead of its name.
This is because in IR+LightTree we have only offsets, so can't navigate
to typealias name element.

^KT-59940 Fixed
This commit is contained in:
Roman Efremov
2023-09-13 17:36:06 +02:00
committed by Space Team
parent ce666182a2
commit ad4d1a5ba8
15 changed files with 88 additions and 65 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.common
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.EXPECT_ACTUAL_ANNOTATION_INCOMPATIBILITY
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.INCOMPATIBILITY
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.DECLARATION_NAME
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.SYMBOL_OWNER_DECLARATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.*
@@ -17,6 +18,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers.MODULE_WITH_PLATFORM
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classFqName
@@ -31,6 +33,7 @@ object CommonBackendErrors {
val INCOMPATIBLE_MATCHING by error3<PsiElement, String, String, ExpectActualCompatibility.Incompatible<*>>()
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning3<PsiElement, IrSymbol, IrSymbol, ExpectActualAnnotationsIncompatibilityType<IrConstructorCall>>()
val EVALUATION_ERROR by error1<PsiElement, String>()
val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error1<PsiElement, IrValueParameter>()
init {
RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages)
@@ -77,6 +80,11 @@ object KtDefaultCommonBackendErrorMessages : BaseDiagnosticRendererFactory() {
"Cannot evaluate constant expression: {0}",
STRING,
)
map.put(
CommonBackendErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE,
"Parameter ''{0}'' has conflicting values in expected and actual annotations.",
DECLARATION_NAME,
)
}
}
@@ -96,4 +104,5 @@ object BackendDiagnosticRenderers {
}
"Annotation `$expectAnnotationFqName` $reason"
}
val DECLARATION_NAME = Renderer<IrDeclarationWithName> { it.name.asString() }
}
@@ -138,6 +138,17 @@ internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportActualAnnotati
)
}
internal fun KtDiagnosticReporterWithImplicitIrBasedContext.reportActualAnnotationConflictingDefaultArgumentValue(
reportOn: IrElement,
file: IrFile,
actualParam: IrValueParameter,
) {
at(reportOn, file).report(
CommonBackendErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE,
actualParam,
)
}
internal fun IrElement.containsOptionalExpectation(): Boolean {
return this is IrClass &&
this.kind == ClassKind.ANNOTATION_CLASS &&
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common.actualizer.checker
import org.jetbrains.kotlin.backend.common.actualizer.reportActualAnnotationConflictingDefaultArgumentValue
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCompatibilityCheckStrategy
internal object IrExpectActualAnnotationConflictingDefaultArgumentValueChecker : IrExpectActualChecker {
override fun check(context: IrExpectActualChecker.Context) = with(context) {
for ((expectSymbol, actualSymbol) in matchedExpectToActual) {
if (expectSymbol !is IrConstructorSymbol || actualSymbol !is IrConstructorSymbol) continue
val expectClass = expectSymbol.owner.parentAsClass
if (expectClass.kind != ClassKind.ANNOTATION_CLASS) continue
val expectValueParams = expectSymbol.owner.valueParameters
val actualValueParams = actualSymbol.owner.valueParameters
if (expectValueParams.size != actualValueParams.size) continue
for ((expectParam, actualParam) in expectValueParams.zip(actualValueParams)) {
val expectDefaultValue = expectParam.defaultValue?.expression ?: continue
val actualDefaultValue = actualParam.defaultValue?.expression ?: continue
with(matchingContext) {
if (!areIrExpressionConstValuesEqual(
expectDefaultValue, actualDefaultValue,
ExpectActualCollectionArgumentsCompatibilityCheckStrategy.Default
)
) {
reportError(expectClass, actualDefaultValue, actualParam)
}
}
}
}
}
private fun IrExpectActualChecker.Context.reportError(
expectAnnotationClass: IrClass,
actualDefaultValue: IrExpression,
actualParam: IrValueParameter,
) {
val actualTypealias = getTypealiasSymbolIfActualizedViaTypealias(expectAnnotationClass, classActualizationInfo)?.owner
if (actualTypealias != null) {
diagnosticsReporter.reportActualAnnotationConflictingDefaultArgumentValue(
actualTypealias, actualTypealias.file, actualParam
)
return
}
diagnosticsReporter.reportActualAnnotationConflictingDefaultArgumentValue(
actualDefaultValue, actualParam.file, actualParam
)
}
}
@@ -20,7 +20,8 @@ internal class IrExpectActualCheckers(
) : IrExpectActualChecker.Context {
private val checkers: Set<IrExpectActualChecker> = setOf(
IrExpectActualAnnotationMatchingChecker
IrExpectActualAnnotationMatchingChecker,
IrExpectActualAnnotationConflictingDefaultArgumentValueChecker,
)
override val matchingContext = object : IrExpectActualMatchingContext(typeSystemContext, classActualizationInfo.actualClasses) {