[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
@@ -3604,13 +3604,6 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE) { firDiagnostic ->
ActualAnnotationConflictingDefaultArgumentValueImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableLikeSymbol(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND) { firDiagnostic ->
ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -2536,11 +2536,6 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val members: List<KtCallableSymbol>
}
interface ActualAnnotationConflictingDefaultArgumentValue : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = ActualAnnotationConflictingDefaultArgumentValue::class
val parameter: KtVariableLikeSymbol
}
interface ExpectedFunctionSourceWithDefaultArgumentsNotFound : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = ExpectedFunctionSourceWithDefaultArgumentsNotFound::class
}
@@ -3057,12 +3057,6 @@ internal class DefaultArgumentsInExpectWithActualTypealiasImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtTypeAlias>(firDiagnostic, token), KtFirDiagnostic.DefaultArgumentsInExpectWithActualTypealias
internal class ActualAnnotationConflictingDefaultArgumentValueImpl(
override val parameter: KtVariableLikeSymbol,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ActualAnnotationConflictingDefaultArgumentValue
internal class ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -1223,10 +1223,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirClassSymbol<*>>("expectClassSymbol")
parameter<Collection<FirCallableSymbol<*>>>("members")
}
val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error<PsiElement> {
parameter<FirVariableSymbol<*>>("parameter")
}
val EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error<PsiElement>()
val NO_ACTUAL_FOR_EXPECT by error<KtNamedDeclaration>(PositioningStrategy.INCOMPATIBLE_DECLARATION) {
@@ -650,7 +650,6 @@ object FirErrors {
val ACTUAL_TYPE_ALIAS_TO_NOTHING by error0<KtTypeAlias>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS by error0<KtFunction>(SourceElementPositioningStrategies.PARAMETERS_WITH_DEFAULT_VALUE)
val DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS by error2<KtTypeAlias, FirClassSymbol<*>, Collection<FirCallableSymbol<*>>>()
val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error1<PsiElement, FirVariableSymbol<*>>()
val EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error0<PsiElement>()
val NO_ACTUAL_FOR_EXPECT by error3<KtNamedDeclaration, FirBasedSymbol<*>, FirModuleData, Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION)
val ACTUAL_WITHOUT_EXPECT by error2<KtNamedDeclaration, FirBasedSymbol<*>, Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY)
@@ -450,7 +450,6 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
"ACTUAL_TYPE_ALIAS_TO_NOTHING",
"ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS",
"DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS",
"ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE",
"EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND",
"NO_ACTUAL_FOR_EXPECT",
"ACTUAL_WITHOUT_EXPECT",
@@ -57,7 +57,6 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION
@@ -1959,11 +1958,6 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
DECLARATION_NAME,
SYMBOLS_ON_NEWLINE_WITH_INDENT,
)
map.put(
ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE,
"Parameter ''{0}'' has conflicting values in expected and actual annotations.",
SYMBOL
)
map.put(
EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND,
"Expected function source is not found, so generating default argument values declared there is impossible. Please add the corresponding file to compilation sources."
@@ -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) {
@@ -13,7 +13,7 @@ sealed class ExpectActualCollectionArgumentsCompatibilityCheckStrategy {
elementsEqual: (T, T) -> Boolean,
): Boolean
internal data object Default : ExpectActualCollectionArgumentsCompatibilityCheckStrategy() {
data object Default : ExpectActualCollectionArgumentsCompatibilityCheckStrategy() {
override fun <T> areCompatible(
expectArg: Collection<T>,
actualArg: Collection<T>,
@@ -1,32 +0,0 @@
// MODULE: m1-common
// FILE: common.kt
expect annotation class A1(val x: Int, val y: String = "OK")
expect annotation class A2(val x: Int = 42, val y: String = "OK")
expect annotation class A3(val x: Int, val y: String)
expect annotation class A4(val x: Int = 42, val y: String)
expect annotation class A5(val x: Int = 42, val y: String)
@A1(0)
@A2
@A3(0, "")
@A4(0, "")
@A5(0, "")
fun test() {}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual annotation class A1(actual val x: Int, actual val y: String)
actual annotation class A2(actual val x: Int, actual val y: String = "OK")
actual annotation class A3(actual val x: Int = 42, actual val y: String = "OK")
actual annotation class A4(actual val x: Int, actual val y: String = "OK")
actual annotation class A5(actual val x: Int = 239, actual val y: String = "OK")
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
@@ -25,7 +25,7 @@ actual typealias A1 = J1
actual typealias A2 = J2
actual typealias A3 = J3
actual typealias A4 = J4
actual typealias A5 = J5
<!ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE!>actual typealias A5 = J5<!>
// FILE: J1.java