diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.fir.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.fir.txt index 2c4f21a6b1b..e01b2a193b4 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.fir.txt @@ -156,3 +156,26 @@ FILE: conflictingProjection.kt public final fun test18(): R|InOuter.OutIntermediate.InInner| { ^test18 R|/InOuter.InOuter|().R|SubstitutionOverride|().R|SubstitutionOverride|() } + public final class TwoParametersOuter : R|kotlin/Any| { + public constructor(): R|TwoParametersOuter| { + super() + } + + public final inner class TwoParametersIntermediate : R|kotlin/Any| { + public constructor(): R|TwoParametersOuter.TwoParametersIntermediate| { + super() + } + + public final inner class InInner : R|kotlin/Any| { + public constructor(): R|TwoParametersOuter.TwoParametersIntermediate.InInner| { + super() + } + + } + + } + + } + public final fun test19(): R|TwoParametersOuter.TwoParametersIntermediate.InInner?| { + ^test19 Null(null) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt index dc0dda94171..6a8c9c63771 100644 --- a/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt @@ -8,10 +8,10 @@ fun a3(value: None) {} fun a4(value: In) {} fun a5(value: In) {} -fun a6(value: In) {} +fun a6(value: In<out Int>) {} fun a7(value: Out) {} -fun a8(value: Out) {} +fun a8(value: Out<in Int>) {} fun a9(value: Out) {} typealias A1 = None @@ -28,26 +28,26 @@ typealias A9<out K> = None typealias A10 = In typealias A11 = In -typealias A12 = In +typealias A12 = In<out K> typealias A13<in K> = In typealias A14<in K> = In -typealias A15<in K> = In +typealias A15<in K> = In<out K> typealias A16<out K> = In typealias A17<out K> = In -typealias A18<out K> = In +typealias A18<out K> = In<out K> typealias A19 = Out -typealias A20 = Out +typealias A20 = Out<in K> typealias A21 = Out typealias A22<in K> = Out -typealias A23<in K> = Out +typealias A23<in K> = Out<in K> typealias A24<in K> = Out typealias A25<out K> = Out -typealias A26<out K> = Out +typealias A26<out K> = Out<in K> typealias A27<out K> = Out class Outer { @@ -83,13 +83,22 @@ class InOuter { fun test10(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() fun test11(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() -fun test12(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() +fun test12(): InOuter<out Int>.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() -fun test13(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() +fun test13(): InOuter.OutIntermediate<in String>.InInner = InOuter().OutIntermediate().InInner() fun test14(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() fun test15(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() -fun test16(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() +fun test16(): InOuter.OutIntermediate.InInner<out Char> = InOuter().OutIntermediate().InInner() fun test17(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() -fun test18(): InOuter.OutIntermediate.InInner = InOuter().OutIntermediate().InInner() +fun test18(): InOuter.OutIntermediate<in String>.InInner<out Char> = InOuter().OutIntermediate().InInner() + +class TwoParametersOuter { + inner class TwoParametersIntermediate { + inner class InInner { + } + } +} + +fun test19(): TwoParametersOuterout String>.TwoParametersIntermediate<in String, Int>.InInner? = null 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 2c97bb44d62..39630db6f05 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 @@ -380,7 +380,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val TYPE_PARAMETERS_IN_OBJECT by error() val ILLEGAL_PROJECTION_USAGE by error() val TYPE_PARAMETERS_IN_ENUM by error() - val CONFLICTING_PROJECTION by error { + val CONFLICTING_PROJECTION by error(PositioningStrategy.VARIANCE_MODIFIER) { parameter("type") } val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error(PositioningStrategy.VARIANCE_MODIFIER) 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 664138a9b07..92843319846 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 @@ -274,7 +274,7 @@ object FirErrors { val TYPE_PARAMETERS_IN_OBJECT by error0() val ILLEGAL_PROJECTION_USAGE by error0() val TYPE_PARAMETERS_IN_ENUM by error0() - val CONFLICTING_PROJECTION by error1() + val CONFLICTING_PROJECTION by error1(SourceElementPositioningStrategies.VARIANCE_MODIFIER) val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error0(SourceElementPositioningStrategies.VARIANCE_MODIFIER) val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0() val REIFIED_TYPE_IN_CATCH_CLAUSE by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirClassVarianceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirClassVarianceChecker.kt index de6a6717531..6e96d86f534 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirClassVarianceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirClassVarianceChecker.kt @@ -154,7 +154,7 @@ object FirClassVarianceChecker : FirClassChecker() { } if (newVariance != null) { - val subTypeRef = extractChildFirTypeRef(typeRef, index) + val subTypeRef = extractTypeArgumentTypeRef(typeRef, index) checkVarianceConflict( typeArgumentType, newVariance, subTypeRef, containingType, @@ -167,7 +167,7 @@ object FirClassVarianceChecker : FirClassChecker() { } } - private fun extractChildFirTypeRef(typeRef: FirTypeRef?, index: Int): FirTypeRef? { + private fun extractTypeArgumentTypeRef(typeRef: FirTypeRef?, index: Int): FirTypeRef? { if (typeRef is FirResolvedTypeRef) { val delegatedTypeRef = typeRef.delegatedTypeRef if (delegatedTypeRef is FirUserTypeRef) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt index 52250e2eeba..33a3009865a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.fir.FirSourceElement 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 @@ -66,9 +67,37 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() { actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE || actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE ) { - reporter.reportOn(typeRef.source, FirErrors.CONFLICTING_PROJECTION, typeRef.coneType, context) - return + val typeArgSource = extractTypeArgumentSource(typeRef, it) + reporter.reportOn(typeArgSource ?: typeRef.source, FirErrors.CONFLICTING_PROJECTION, typeRef.coneType, context) } } } + + private fun extractTypeArgumentSource(typeRef: FirTypeRef, index: Int): FirSourceElement? { + if (typeRef is FirResolvedTypeRef) { + val delegatedTypeRef = typeRef.delegatedTypeRef + if (delegatedTypeRef is FirUserTypeRef) { + var currentTypeArguments: List? = null + var currentIndex = index + val qualifier = delegatedTypeRef.qualifier + + for (i in qualifier.size - 1 downTo 0) { + val typeArguments = qualifier[i].typeArgumentList.typeArguments + if (currentIndex < typeArguments.size) { + currentTypeArguments = typeArguments + break + } else { + currentIndex -= typeArguments.size + } + } + + val typeArgument = currentTypeArguments?.elementAtOrNull(currentIndex) + if (typeArgument is FirTypeProjectionWithVariance) { + return typeArgument.source + } + } + } + + return null + } } diff --git a/compiler/testData/cli/jvm/conflictingProjection.out b/compiler/testData/cli/jvm/conflictingProjection.out index 7c52b2f14c5..a4b264b8848 100644 --- a/compiler/testData/cli/jvm/conflictingProjection.out +++ b/compiler/testData/cli/jvm/conflictingProjection.out @@ -1,9 +1,9 @@ warning: ATTENTION! This build uses in-dev FIR: -Xuse-fir -compiler/testData/cli/jvm/conflictingProjection.kt:10:15: error: projection is conflicting with variance of the corresponding type parameter of Out. Remove the projection or replace it with '*' +compiler/testData/cli/jvm/conflictingProjection.kt:10:19: error: projection is conflicting with variance of the corresponding type parameter of Out. Remove the projection or replace it with '*' fun a8(value: Out) {} - ^ + ^ compiler/testData/cli/jvm/conflictingProjection.kt:17:15: error: variance annotations are only allowed for type parameters of classes and interfaces typealias A13 = In ^ @@ -13,7 +13,7 @@ typealias A14 = In compiler/testData/cli/jvm/conflictingProjection.kt:19:15: error: variance annotations are only allowed for type parameters of classes and interfaces typealias A15 = In ^ -compiler/testData/cli/jvm/conflictingProjection.kt:19:23: error: projection is conflicting with variance of the corresponding type parameter of In. Remove the projection or replace it with '*' +compiler/testData/cli/jvm/conflictingProjection.kt:19:26: error: projection is conflicting with variance of the corresponding type parameter of In. Remove the projection or replace it with '*' typealias A15 = In - ^ + ^ COMPILATION_ERROR diff --git a/compiler/testData/diagnostics/tests/declarationChecks/ConflictingAndRedundantProjections.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/ConflictingAndRedundantProjections.fir.kt index fe6c82df921..107683a2e03 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/ConflictingAndRedundantProjections.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/ConflictingAndRedundantProjections.fir.kt @@ -4,11 +4,11 @@ class Inv class X fun f1(p: In) {} -fun f2(p: In) {} +fun f2(p: In<out X>) {} fun f3(p: In) {} fun f4(p: Out) {} -fun f5(p: Out) {} +fun f5(p: Out<in X>) {} fun f6(p: Out) {} fun f6(p: Inv) {} diff --git a/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt b/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt index e278af9d41b..124d0cbdfe5 100644 --- a/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/kt39220.fir.kt @@ -51,7 +51,7 @@ val String.x1 get() = "" fun bar1(f: KFunction2) {} -fun bar2(f: KFunction2) {} +fun bar2(f: KFunction2<out K, String, String>) {} fun bar3(f: Any?) {} diff --git a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.fir.kt b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.fir.kt index 85ccadecf5b..d7ac11cf6c6 100644 --- a/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/overloadConflicts/genericWithProjection.fir.kt @@ -7,5 +7,5 @@ class In() { fun test1(x: In): Unit = x.f("1") fun test2(x: In): Unit = x.f("1") -fun test3(x: In): Unit = x.f("1") -fun test4(x: In<*>): Unit = x.f("1") \ No newline at end of file +fun test3(x: In<out String>): Unit = x.f("1") +fun test4(x: In<*>): Unit = x.f("1") diff --git a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt index 03af30bf1f1..3bb8038aa36 100644 --- a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt @@ -6,8 +6,8 @@ interface Out typealias InAlias = In typealias OutAlias = Out -typealias TestOutForIn = In -typealias TestInForOut = Out +typealias TestOutForIn = In<out T> +typealias TestInForOut = Out<in T> typealias TestOutForInWithinAlias = InAlias typealias TestInForOutWithinAlias = OutAlias diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt index 351a2a1ab03..49b7e961365 100644 --- a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt @@ -6,11 +6,11 @@ class Inv typealias In1 = In typealias In2 = In -typealias In3 = In +typealias In3 = In<out T> typealias In4 = In<*> typealias Out1 = Out -typealias Out2 = Out +typealias Out2 = Out<in T> typealias Out3 = Out typealias Out4 = Out<*> diff --git a/compiler/testData/diagnostics/tests/variance/InPosition.fir.kt b/compiler/testData/diagnostics/tests/variance/InPosition.fir.kt index a353a4ffc6a..6624f7be513 100644 --- a/compiler/testData/diagnostics/tests/variance/InPosition.fir.kt +++ b/compiler/testData/diagnostics/tests/variance/InPosition.fir.kt @@ -35,7 +35,7 @@ interface Test { fun neOk6(i: In>")!>O>>) fun neOk7(i: Pair, O>")!>I>, , O>")!>O>) fun neOk8(i: Inv")!>O>) - fun neOk9(i: In) + fun neOk9(i: In<out P>) fun neOk10(i: Out<")!>O>) fun neOk11(i: Inv")!>I>) diff --git a/compiler/testData/diagnostics/tests/variance/InvariantPosition.fir.kt b/compiler/testData/diagnostics/tests/variance/InvariantPosition.fir.kt index 4513bda053d..8989b7dac66 100644 --- a/compiler/testData/diagnostics/tests/variance/InvariantPosition.fir.kt +++ b/compiler/testData/diagnostics/tests/variance/InvariantPosition.fir.kt @@ -23,7 +23,7 @@ interface Test { var neOk7: Pair, O>")!>I>, , O>")!>O> var neOk8: Inv")!>O> var neOk9: Inv")!>I> - var neOk10: In + var neOk10: In<out I> var neOk11: I var neOk12: In<")!>O> diff --git a/compiler/testData/diagnostics/tests/variance/OutPosition.fir.kt b/compiler/testData/diagnostics/tests/variance/OutPosition.fir.kt index abef9b833cb..aab70b319be 100644 --- a/compiler/testData/diagnostics/tests/variance/OutPosition.fir.kt +++ b/compiler/testData/diagnostics/tests/variance/OutPosition.fir.kt @@ -21,20 +21,20 @@ interface Test { fun ok12(): Inv fun ok13(): Inv - fun neOk1(): I - fun neOk2(): In<O> - fun neOk3(): InI>> - fun neOk4(): Inv<I> - fun neOk5(): Inv<O> - fun neOk6(): PairO>, I> - fun neOk7(): InvO> - fun neOk8(): Out + fun neOk1(): I + fun neOk2(): In<")!>O> + fun neOk3(): In>")!>I>> + fun neOk4(): Inv<")!>I> + fun neOk5(): Inv<")!>O> + fun neOk6(): Pair, I>")!>O>, , I>")!>I> + fun neOk7(): Inv")!>O> + fun neOk8(): Out<")!>in I> - fun neOk10(): InvO> - fun neOk11(): InvI> + fun neOk10(): Inv")!>O> + fun neOk11(): Inv")!>I> fun neOk30(): Pair - fun neOk31(): Pair<I, Inv> + fun neOk31(): Pair<")!>I, Inv> fun neOk32(): Inv fun neOk33(): Inv<> fun neOk34(): Inv<C> 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 99d600c0497..93c6dd847a8 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 @@ -840,7 +840,7 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = TypeParametersInEnum::class } - abstract class ConflictingProjection : KtFirDiagnostic() { + abstract class ConflictingProjection : KtFirDiagnostic() { override val diagnosticClass get() = ConflictingProjection::class abstract val type: KtType } 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 151597931e3..e4ee4dbb717 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 @@ -1358,7 +1358,7 @@ internal class ConflictingProjectionImpl( override val type: KtType, firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, -) : KtFirDiagnostic.ConflictingProjection(), KtAbstractFirDiagnostic { +) : KtFirDiagnostic.ConflictingProjection(), KtAbstractFirDiagnostic { override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) }