[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, 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 -> add(FirErrors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND) { firDiagnostic ->
ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl( ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl(
firDiagnostic as KtPsiDiagnostic, firDiagnostic as KtPsiDiagnostic,
@@ -2536,11 +2536,6 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val members: List<KtCallableSymbol> val members: List<KtCallableSymbol>
} }
interface ActualAnnotationConflictingDefaultArgumentValue : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = ActualAnnotationConflictingDefaultArgumentValue::class
val parameter: KtVariableLikeSymbol
}
interface ExpectedFunctionSourceWithDefaultArgumentsNotFound : KtFirDiagnostic<PsiElement> { interface ExpectedFunctionSourceWithDefaultArgumentsNotFound : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = ExpectedFunctionSourceWithDefaultArgumentsNotFound::class override val diagnosticClass get() = ExpectedFunctionSourceWithDefaultArgumentsNotFound::class
} }
@@ -3057,12 +3057,6 @@ internal class DefaultArgumentsInExpectWithActualTypealiasImpl(
token: KtLifetimeToken, token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtTypeAlias>(firDiagnostic, token), KtFirDiagnostic.DefaultArgumentsInExpectWithActualTypealias ) : 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( internal class ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl(
firDiagnostic: KtPsiDiagnostic, firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken, token: KtLifetimeToken,
@@ -1223,10 +1223,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirClassSymbol<*>>("expectClassSymbol") parameter<FirClassSymbol<*>>("expectClassSymbol")
parameter<Collection<FirCallableSymbol<*>>>("members") 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 EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error<PsiElement>()
val NO_ACTUAL_FOR_EXPECT by error<KtNamedDeclaration>(PositioningStrategy.INCOMPATIBLE_DECLARATION) { 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_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 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 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 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 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) 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_TYPE_ALIAS_TO_NOTHING",
"ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS", "ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS",
"DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS", "DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS",
"ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE",
"EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND", "EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND",
"NO_ACTUAL_FOR_EXPECT", "NO_ACTUAL_FOR_EXPECT",
"ACTUAL_WITHOUT_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.ABSTRACT_SUPER_CALL_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY 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_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_FUNCTION_WITH_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION
@@ -1959,11 +1958,6 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
DECLARATION_NAME, DECLARATION_NAME,
SYMBOLS_ON_NEWLINE_WITH_INDENT, 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( map.put(
EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND, 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." "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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.BackendDiagnosticRenderers.EXPECT_ACTUAL_ANNOTATION_INCOMPATIBILITY 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.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.backend.common.BackendDiagnosticRenderers.SYMBOL_OWNER_DECLARATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.* 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.Renderers.MODULE_WITH_PLATFORM
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName 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.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.classFqName import org.jetbrains.kotlin.ir.types.classFqName
@@ -31,6 +33,7 @@ object CommonBackendErrors {
val INCOMPATIBLE_MATCHING by error3<PsiElement, String, String, ExpectActualCompatibility.Incompatible<*>>() val INCOMPATIBLE_MATCHING by error3<PsiElement, String, String, ExpectActualCompatibility.Incompatible<*>>()
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning3<PsiElement, IrSymbol, IrSymbol, ExpectActualAnnotationsIncompatibilityType<IrConstructorCall>>() val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning3<PsiElement, IrSymbol, IrSymbol, ExpectActualAnnotationsIncompatibilityType<IrConstructorCall>>()
val EVALUATION_ERROR by error1<PsiElement, String>() val EVALUATION_ERROR by error1<PsiElement, String>()
val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error1<PsiElement, IrValueParameter>()
init { init {
RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages) RootDiagnosticRendererFactory.registerFactory(KtDefaultCommonBackendErrorMessages)
@@ -77,6 +80,11 @@ object KtDefaultCommonBackendErrorMessages : BaseDiagnosticRendererFactory() {
"Cannot evaluate constant expression: {0}", "Cannot evaluate constant expression: {0}",
STRING, 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" "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 { internal fun IrElement.containsOptionalExpectation(): Boolean {
return this is IrClass && return this is IrClass &&
this.kind == ClassKind.ANNOTATION_CLASS && 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 { ) : IrExpectActualChecker.Context {
private val checkers: Set<IrExpectActualChecker> = setOf( private val checkers: Set<IrExpectActualChecker> = setOf(
IrExpectActualAnnotationMatchingChecker IrExpectActualAnnotationMatchingChecker,
IrExpectActualAnnotationConflictingDefaultArgumentValueChecker,
) )
override val matchingContext = object : IrExpectActualMatchingContext(typeSystemContext, classActualizationInfo.actualClasses) { override val matchingContext = object : IrExpectActualMatchingContext(typeSystemContext, classActualizationInfo.actualClasses) {
@@ -13,7 +13,7 @@ sealed class ExpectActualCollectionArgumentsCompatibilityCheckStrategy {
elementsEqual: (T, T) -> Boolean, elementsEqual: (T, T) -> Boolean,
): Boolean ): Boolean
internal data object Default : ExpectActualCollectionArgumentsCompatibilityCheckStrategy() { data object Default : ExpectActualCollectionArgumentsCompatibilityCheckStrategy() {
override fun <T> areCompatible( override fun <T> areCompatible(
expectArg: Collection<T>, expectArg: Collection<T>,
actualArg: 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 // MODULE: m1-common
// FILE: common.kt // FILE: common.kt
@@ -25,7 +25,7 @@ actual typealias A1 = J1
actual typealias A2 = J2 actual typealias A2 = J2
actual typealias A3 = J3 actual typealias A3 = J3
actual typealias A4 = J4 actual typealias A4 = J4
actual typealias A5 = J5 <!ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE!>actual typealias A5 = J5<!>
// FILE: J1.java // FILE: J1.java