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 4b038bd6029..7a030d1f5e0 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 @@ -253,8 +253,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val INFERENCE_ERROR by error() val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error() val UPPER_BOUND_VIOLATED by error { - parameter("typeParameter") - parameter("violatedType") + parameter("upperBound") } val TYPE_ARGUMENTS_NOT_ALLOWED by error() val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error { 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 c4523f77a90..b2b35c7bd72 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 @@ -197,7 +197,7 @@ object FirErrors { val RECURSION_IN_IMPLICIT_TYPES by error0() val INFERENCE_ERROR by error0() val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0() - val UPPER_BOUND_VIOLATED by error2() + val UPPER_BOUND_VIOLATED by error1() val TYPE_ARGUMENTS_NOT_ALLOWED by error0() val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2>() val NO_TYPE_ARGUMENTS_ON_RHS by error2>() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt index e72a8d6f142..4be43d8e180 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirUpperBoundViolatedChecker.kt @@ -68,8 +68,9 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { return@forEach } - if (!satisfiesBounds(proto, actual.coneType, substitutor, context.session.typeContext)) { - reporter.reportOn(actual.source, proto, actual.coneType, context) + val upperBound = getSubstitutedUpperBound(proto, substitutor, context.session.typeContext) + if (upperBound != null && !satisfiesBounds(upperBound, actual.coneType, context.session.typeContext)) { + reporter.reportOn(actual.source, upperBound, context) return } @@ -164,7 +165,7 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection) if (!satisfiesBounds) { - reporter.reportOn(functionCall.source, proto, actual, context) + reporter.reportOn(functionCall.source, intersection, context) return } } @@ -212,9 +213,10 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { ) parameterPairs.forEach { (proto, actual) -> - if (!satisfiesBounds(proto, actual.type, substitutor, typeSystemContext)) { + val upperBound = getSubstitutedUpperBound(proto, substitutor, typeSystemContext) + if (upperBound != null && !satisfiesBounds(upperBound, actual.type, typeSystemContext)) { // should report on the parameter instead! - reporter.reportOn(reportTarget, proto, actual, context) + reporter.reportOn(reportTarget, upperBound, context) return true } @@ -233,25 +235,30 @@ object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() { * bounds of the prototypeSymbol. */ private fun satisfiesBounds( - prototypeSymbol: FirTypeParameterSymbol, + upperBound: ConeKotlinType, target: ConeKotlinType, - substitutor: ConeSubstitutor, typeSystemContext: ConeTypeContext ): Boolean { - var intersection = typeSystemContext.intersectTypes( - prototypeSymbol.fir.bounds.map { it.coneType } - ).safeAs() ?: return true + return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false) + } - intersection = substitutor.substituteOrSelf(intersection) - return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, intersection, stubTypesEqualToAnything = false) + private fun getSubstitutedUpperBound( + prototypeSymbol: FirTypeParameterSymbol, + substitutor: ConeSubstitutor, + typeSystemContext: ConeTypeContext + ): ConeKotlinType? { + val intersection = typeSystemContext.intersectTypes( + prototypeSymbol.fir.bounds.map { it.coneType } + ).safeAs() ?: return null + + return substitutor.substituteOrSelf(intersection) } private fun DiagnosticReporter.reportOn( source: FirSourceElement?, - proto: FirTypeParameterSymbol, actual: ConeKotlinType, context: CheckerContext ) { - reportOn(source, FirErrors.UPPER_BOUND_VIOLATED, proto, actual, context) + reportOn(source, FirErrors.UPPER_BOUND_VIOLATED, actual, context) } } 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 80b02190c1a..0b91a829183 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 @@ -404,7 +404,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { map.put(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types") map.put(INFERENCE_ERROR, "Inference error") map.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties") - map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", TO_STRING, TO_STRING) + map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE) map.put(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // * map.put( WRONG_NUMBER_OF_TYPE_ARGUMENTS, 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 35baed53938..77a56efaa8f 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 @@ -772,8 +772,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert } add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic -> UpperBoundViolatedImpl( - firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir), - firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b), + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), firDiagnostic as FirPsiDiagnostic<*>, token, ) 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 af1b7e5d6bb..7335f525051 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 @@ -553,8 +553,7 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract class UpperBoundViolated : KtFirDiagnostic() { override val diagnosticClass get() = UpperBoundViolated::class - abstract val typeParameter: KtTypeParameterSymbol - abstract val violatedType: KtType + abstract val upperBound: KtType } abstract class TypeArgumentsNotAllowed : KtFirDiagnostic() { 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 15959dc34be..485df0ef79e 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 @@ -883,8 +883,7 @@ internal class ProjectionOnNonClassTypeArgumentImpl( } internal class UpperBoundViolatedImpl( - override val typeParameter: KtTypeParameterSymbol, - override val violatedType: KtType, + override val upperBound: KtType, firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, ) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic { diff --git a/idea/testData/checker/Bounds.fir.kt b/idea/testData/checker/Bounds.fir.kt index d4852f6eb24..ab196ced66b 100644 --- a/idea/testData/checker/Bounds.fir.kt +++ b/idea/testData/checker/Bounds.fir.kt @@ -4,7 +4,7 @@ class Pair abstract class C, X : (B) -> Pair, B>>() : B() { // 2 errors - val a = B<Char>() // error + val a = B<Char>() // error abstract val x : (B) -> B } diff --git a/idea/testData/checker/Bounds2.fir.kt b/idea/testData/checker/Bounds2.fir.kt index 9d5a48881bd..bb0b58eba8b 100644 --- a/idea/testData/checker/Bounds2.fir.kt +++ b/idea/testData/checker/Bounds2.fir.kt @@ -1,10 +1,10 @@ fun test() { - foo<Int?>() + foo<Int?>() foo() bar() bar() - bar<Double?>() - bar<Double>() + bar<Double?>() + bar<Double>() 1.buzz() } diff --git a/idea/testData/checker/BoundsWithSubstitutors.fir.kt b/idea/testData/checker/BoundsWithSubstitutors.fir.kt index a904462848d..d28a7c3fae2 100644 --- a/idea/testData/checker/BoundsWithSubstitutors.fir.kt +++ b/idea/testData/checker/BoundsWithSubstitutors.fir.kt @@ -6,10 +6,10 @@ class C : A() val a = B() - val a1 = B<Int>() + val a1 = B<Int>() class X() val b = X, C>>() - val b0 = XAny?>() - val b1 = XX, String>>() + val b0 = XAny?>() + val b1 = XX, String>>() diff --git a/idea/testData/checker/MultipleBounds.fir.kt b/idea/testData/checker/MultipleBounds.fir.kt index 60363170b58..a9857333254 100644 --- a/idea/testData/checker/MultipleBounds.fir.kt +++ b/idea/testData/checker/MultipleBounds.fir.kt @@ -30,8 +30,8 @@ class Test1() } fun test() { - Test1<B>() - Test1<A>() + Test1<B>() + Test1<A>() Test1() }