diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/multipleBounds.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/multipleBounds.kt index ee395cf250d..cad212e0616 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/multipleBounds.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/multipleBounds.kt @@ -9,9 +9,9 @@ interface B { } interface G { - val boo: Double where X : A, X : B - val bal: Double where A : B - val bas: Double where Y : B, X : B + val <X> boo: Double where X : A, X : B + val <A> bal: Double where A : B + val <Y> bas: Double where Y : B, X : B } class C() : A(), B @@ -66,4 +66,4 @@ val t1 = test2(A()) val t2 = test2(C()) val t3 = test2(C()) -val x : Int = 0 +val <T, B : T> x : Int = 0 diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 5877dc37fc6..107a21ba47a 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -330,6 +330,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() { parameter("expected") parameter("actual") } + + val CYCLIC_GENERIC_UPPER_BOUND by error() } val REFLECTION by object : DiagnosticGroup("Reflection") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 7abd37a721a..59f937bc5ec 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -240,6 +240,7 @@ object FirErrors { val TYPE_PARAMETERS_NOT_ALLOWED by error0() val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0() val RETURN_TYPE_MISMATCH by error2(SourceElementPositioningStrategies.WHOLE_ELEMENT) + val CYCLIC_GENERIC_UPPER_BOUND by error0() // Reflection val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt new file mode 100644 index 00000000000..d06f5754e95 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirCyclicTypeBoundsChecker.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2021 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.fir.analysis.checkers.declaration + +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +object FirCyclicTypeBoundsChecker : FirMemberDeclarationChecker() { + + override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration is FirConstructor || declaration is FirTypeAlias) return + + val processed = mutableSetOf() + val cycles = mutableSetOf() + val graph = declaration.typeParameters.map { param -> + param.symbol.name to param.symbol.fir.bounds.flatMap { extractTypeParamNames(it) }.toSet() + }.toMap() + + declaration.typeParameters.forEach { param -> + if (!processed.contains(param.symbol.name)) { + findCycles( + persistentListOf(), + param.symbol.name, + processed, + mutableSetOf(), + cycles + ) { name -> graph.getOrDefault(name, emptySet()) } + } + } + + if (cycles.isNotEmpty()) { + declaration.typeParameters + .filter { cycles.contains(it.symbol.name) } + .forEach { param -> + val targets = if (declaration is FirRegularClass) { + param.symbol.fir.originalBounds().filter { cycles.contains(extractTypeParamName(it.coneType)) } + .mapNotNull { it.source } + } else { + listOf(param.source) + } + targets.forEach { + reporter.reportOn(it, FirErrors.CYCLIC_GENERIC_UPPER_BOUND, context) + } + } + } + } + + private fun FirTypeParameter.originalBounds() = bounds.flatMap { it.unwrapBound() } + + private fun FirTypeRef.unwrapBound(): List = + if (this is FirErrorTypeRef && diagnostic is ConeCyclicTypeBound) { + (diagnostic as ConeCyclicTypeBound).bounds + } else { + listOf(this) + } + + + private fun extractTypeParamNames(ref: FirTypeRef): Set = + ref.unwrapBound().mapNotNull { extractTypeParamName(it.coneType) }.toSet() + + private fun extractTypeParamName(type: ConeKotlinType): Name? = type.safeAs()?.lookupTag?.name + + private fun findCycles( + path: PersistentList, + node: Name, + processed: MutableSet, + visited: MutableSet, + cycles: MutableSet, + graph: (Name) -> Set + ) { + processed.add(node) + if (visited.add(node)) { + val newPath = path.add(node) + graph(node).forEach { nextNode -> + findCycles(newPath, nextNode, processed, visited, cycles, graph) + } + } else { + cycles.addAll(path.dropWhile { it != node }) + } + } + +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index bf299aaac89..290cee9c4cd 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -70,6 +70,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_DE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_GETTER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_WITH_NON_CONST_INITIALIZER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_GENERIC_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_NOT_PROPERTY_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_VARARG_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DATA_CLASS_WITHOUT_PARAMETERS @@ -509,6 +510,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(RETURN_TYPE_MISMATCH, "Return type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE) + map.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds") + // Reflection map.put( EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED, diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index 6beb6a9fdc7..d86647826c3 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -26,6 +26,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirExposedVisibilityDeclarationChecker, FirSealedSupertypeChecker, FirTypeAliasChecker, + FirCyclicTypeBoundsChecker, ) override val functionCheckers: Set = setOf( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index 6489e299c81..9807b76df51 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.diagnostics +import kotlinx.collections.immutable.ImmutableList import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.render @@ -15,6 +16,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability @@ -114,6 +116,10 @@ class ConeTypeParameterInQualifiedAccess(val symbol: FirTypeParameterSymbol) : C override val reason: String get() = "Type parameter ${symbol.fir.name} in qualified access" } +class ConeCyclicTypeBound(val symbol: FirTypeParameterSymbol, val bounds: ImmutableList) : ConeDiagnostic() { + override val reason: String get() = "Type parameter ${symbol.fir.name} has cyclic bounds" +} + private fun describeSymbol(symbol: AbstractFirBasedSymbol<*>): String { return when (symbol) { is FirClassLikeSymbol<*> -> symbol.classId.asString() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 9a8de8f2ced..1ceb46e4520 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers +import kotlinx.collections.immutable.toImmutableList import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall @@ -12,9 +13,11 @@ import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.createImportingScopes import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef class FirTypeResolveProcessor( @@ -140,9 +143,11 @@ class FirTypeResolveTransformer( for (typeParameter in typeParametersOwner.typeParameters) { if (typeParameter !is FirTypeParameter) continue if (hasSupertypePathToParameter(typeParameter, typeParameter, mutableSetOf())) { - // TODO: Report diagnostic somewhere + val errorType = buildErrorTypeRef { + diagnostic = ConeCyclicTypeBound(typeParameter.symbol, typeParameter.bounds.toImmutableList()) + } typeParameter.replaceBounds( - listOf(session.builtinTypes.nullableAnyType) + listOf(errorType) ) } } diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.fir.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.fir.kt deleted file mode 100644 index e51939427e4..00000000000 --- a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -fun foo1() {} - -fun foo2() {} - -fun foo3() where T : F?, F : T {} - -fun foo4() where T : F?, F : E, E : F? {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt index b63add0945b..96ee9837135 100644 --- a/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/functions.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun <T : F?, F : T?> foo1() {} fun F : E, E : F?> foo2() {} diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.fir.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.fir.kt deleted file mode 100644 index aa08e862771..00000000000 --- a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -class A1 - -class A2 - -class A3 where T : F?, F : T? - -class A4 where T : F?, F : E, E : F \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt index 3e4a0209ee1..cc732610b73 100644 --- a/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt +++ b/compiler/testData/diagnostics/tests/generics/cyclicBounds/inClass.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class A1F?, F : T?> class A2E, E : F?> diff --git a/compiler/testData/diagnostics/tests/inference/commonSuperTypeOfTypesWithErrorSupertypes.fir.kt b/compiler/testData/diagnostics/tests/inference/commonSuperTypeOfTypesWithErrorSupertypes.fir.kt index 6e6071bae27..6ab18edddc3 100644 --- a/compiler/testData/diagnostics/tests/inference/commonSuperTypeOfTypesWithErrorSupertypes.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/commonSuperTypeOfTypesWithErrorSupertypes.fir.kt @@ -7,7 +7,7 @@ interface Foo { fun select(vararg args: S): S = TODO() -class Bar : Foo { +class BarB> : Foo { val v = select( getSum(), 42 diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.fir.kt deleted file mode 100644 index 1b4dd0f6705..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.fir.kt +++ /dev/null @@ -1,3 +0,0 @@ -// !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER -fun foo() {} -val prop \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt index 6d80f09022d..b21d39c09ac 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBound.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER fun <T: T?> foo() {} val <T: T?> prop \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.fir.kt deleted file mode 100644 index c826cffed8c..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.fir.kt +++ /dev/null @@ -1 +0,0 @@ -class MyClass \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.kt index 7745a4f9972..7391e99abcd 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClass.kt @@ -1 +1,2 @@ +// FIR_IDENTICAL class MyClassT?> \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.fir.kt deleted file mode 100644 index eef2a5ca164..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.fir.kt +++ /dev/null @@ -1 +0,0 @@ -class MyClass \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.kt index 47ec80cc903..c5b9777564a 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundInClassNotNull.kt @@ -1 +1,2 @@ +// FIR_IDENTICAL class MyClassT> \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.fir.kt deleted file mode 100644 index 7d7a00b32d5..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.fir.kt +++ /dev/null @@ -1,5 +0,0 @@ -// !DIAGNOSTICS: -MUST_BE_INITIALIZED_OR_BE_ABSTRACT -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER -class My { - fun foo() {} - val prop: T -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt index 4ab350e74cc..47c8547bada 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundMember.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -MUST_BE_INITIALIZED_OR_BE_ABSTRACT -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER class My { fun <T: T?> foo() {} diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.fir.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.fir.kt deleted file mode 100644 index 7d0c85088b6..00000000000 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.fir.kt +++ /dev/null @@ -1,3 +0,0 @@ -// !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER -fun foo() {} -val prop: T \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt index 3fe62f6097a..b0a8a5c4ca1 100644 --- a/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt +++ b/compiler/testData/diagnostics/tests/regressions/itselfAsUpperBoundNotNull.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -MUST_BE_INITIALIZED -TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER fun <T: T> foo() {} val <T: T?> prop: T \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/kt36951.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36951.fir.kt index 73682ace08f..aea907c3ae8 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/kt36951.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/kt36951.fir.kt @@ -2,7 +2,7 @@ // !LANGUAGE: +NewInference // !DIAGNOSTICS: -UNUSED_PARAMETER -class Base : HashSet() { +class BaseT> : HashSet() { fun foo() { super.remove("") } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index cb1ebe9609d..594c42d159b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1018,6 +1018,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.CYCLIC_GENERIC_UPPER_BOUND) { firDiagnostic -> + CyclicGenericUpperBoundImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic -> ExtensionInClassReferenceNotAllowedImpl( firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 177910908fe..6febbd4abc1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -723,6 +723,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val actual: KtType } + abstract class CyclicGenericUpperBound : KtFirDiagnostic() { + override val diagnosticClass get() = CyclicGenericUpperBound::class + } + abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic() { override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class abstract val referencedDeclaration: KtCallableSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 8461c478647..ac0a9e27a29 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1168,6 +1168,13 @@ internal class ReturnTypeMismatchImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class CyclicGenericUpperBoundImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.CyclicGenericUpperBound(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class ExtensionInClassReferenceNotAllowedImpl( override val referencedDeclaration: KtCallableSymbol, firDiagnostic: FirPsiDiagnostic<*>,