From 03e577bf980e443004307051751f7c74debcc965 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Tue, 1 Jun 2021 16:22:02 +0300 Subject: [PATCH] [FIR] Implement CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION diagnostics, fix tests --- .../resolve/typeAliasWithTypeArguments.kt | 4 +-- .../diagnostics/FirDiagnosticsList.kt | 3 ++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../FirConflictingProjectionChecker.kt | 36 +++++++++++-------- .../diagnostics/FirDefaultErrorMessages.kt | 6 ++++ .../typealias/conflictingProjections.fir.kt | 8 ++--- .../typealias/substitutionVariance.fir.kt | 20 +++++------ .../diagnostics/KtFirDataClassConverters.kt | 7 ++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 8 +++++ 10 files changed, 67 insertions(+), 31 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/typeAliasWithTypeArguments.kt b/compiler/fir/analysis-tests/testData/resolve/typeAliasWithTypeArguments.kt index 3bd1b472d05..1e260168afd 100644 --- a/compiler/fir/analysis-tests/testData/resolve/typeAliasWithTypeArguments.kt +++ b/compiler/fir/analysis-tests/testData/resolve/typeAliasWithTypeArguments.kt @@ -71,13 +71,13 @@ typealias Out1 = Out typealias Invariant1 = Invariant -fun test_5(a: A, in1: In1, in2: In1, in3: In1) { +fun test_5(a: A, in1: In1, in2: In1, in3: In1<out A>) { in1.take(a) in2.take(a) in3.take(a) } -fun test_6(a: A, out1: Out1, out2: Out1, out3: Out1) { +fun test_6(a: A, out1: Out1, out2: Out1<in A>, out3: Out1) { out1.value().foo() out2.value().foo() out3.value().foo() 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 39630db6f05..653bdfb8c1f 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 @@ -383,6 +383,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val CONFLICTING_PROJECTION by error(PositioningStrategy.VARIANCE_MODIFIER) { parameter("type") } + val CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION by error(PositioningStrategy.VARIANCE_MODIFIER) { + parameter("type") + } val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error(PositioningStrategy.VARIANCE_MODIFIER) val CATCH_PARAMETER_WITH_DEFAULT_VALUE 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 92843319846..f0b0043b757 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 @@ -275,6 +275,7 @@ object FirErrors { val ILLEGAL_PROJECTION_USAGE by error0() val TYPE_PARAMETERS_IN_ENUM by error0() val CONFLICTING_PROJECTION by error1(SourceElementPositioningStrategies.VARIANCE_MODIFIER) + val CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION 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/FirConflictingProjectionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictingProjectionChecker.kt index 33a3009865a..8dd79479ced 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,13 +5,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.fir.FirFakeSourceElementKind 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 import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.addToStdlib.safeAs @@ -41,34 +42,39 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() { } } - private fun checkTypeRef(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { - val declaration = typeRef.coneTypeSafe() - ?.lookupTag - ?.toSymbol(context.session) - ?.fir.safeAs() - ?: return + private fun checkTypeRef( + typeRef: FirTypeRef, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + val type = typeRef.coneTypeSafe() + val fullyExpandedType = type?.fullyExpandedType(context.session) ?: return + val declaration = fullyExpandedType.toSymbol(context.session)?.fir.safeAs() ?: return val size = minOf(declaration.typeParameters.size, typeRef.coneType.typeArguments.size) for (it in 0 until size) { val proto = declaration.typeParameters[it] val actual = typeRef.coneType.typeArguments[it] + val fullyExpandedProjection = fullyExpandedType.typeArguments[it] val protoVariance = proto.safeAs() ?.symbol?.fir ?.variance - ?: continue - - if (protoVariance == Variance.INVARIANT) { - continue - } if ( - actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE || - actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE + (fullyExpandedProjection is ConeKotlinTypeConflictingProjection || + actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE || + actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE) && + typeRef.source?.kind !is FirFakeSourceElementKind ) { val typeArgSource = extractTypeArgumentSource(typeRef, it) - reporter.reportOn(typeArgSource ?: typeRef.source, FirErrors.CONFLICTING_PROJECTION, typeRef.coneType, context) + reporter.reportOn( + typeArgSource ?: typeRef.source, + if (type != fullyExpandedType) FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION else FirErrors.CONFLICTING_PROJECTION, + fullyExpandedType, + 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 07c3d7ffbf3..6f3863f0e6a 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.COMPONENT_FUNCTIO import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONDITION_TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_UPPER_BOUNDS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT @@ -610,6 +611,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { "Projection is conflicting with variance of the corresponding type parameter of {0}. Remove the projection or replace it with ''*''", RENDER_TYPE ) + map.put( + CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, + "Conflicting projection in type alias expansion in intermediate type '{0}'", + RENDER_TYPE + ) map.put( VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces" diff --git a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt index 3bb8038aa36..e4c32fc0d22 100644 --- a/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/conflictingProjections.fir.kt @@ -9,8 +9,8 @@ typealias OutAlias = Out typealias TestOutForIn = In<out T> typealias TestInForOut = Out<in T> -typealias TestOutForInWithinAlias = InAlias -typealias TestInForOutWithinAlias = OutAlias +typealias TestOutForInWithinAlias = InAlias<out T> +typealias TestInForOutWithinAlias = OutAlias<in T> -fun testOutForInWithinResolvedType(x: InAlias) {} -fun testInForOutWithinResolvedType(x: OutAlias) {} +fun testOutForInWithinResolvedType(x: InAlias<out T>) {} +fun testInForOutWithinResolvedType(x: OutAlias<in T>) {} diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt index 49b7e961365..13c04c13877 100644 --- a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.fir.kt @@ -23,31 +23,31 @@ val inv1: Inv1 = Inv() fun inInv_Inv(x: In1) = x fun inInv_In(x: In1) = x -fun inInv_Out(x: In1) = x +fun inInv_Out(x: In1<out Int>) = x fun inInv_Star(x: In1<*>) = x fun inIn_Inv(x: In2) = x fun inIn_In(x: In2) = x -fun inIn_Out(x: In2) = x +fun inIn_Out(x: In2<out Int>) = x fun inIn_Star(x: In2<*>) = x fun inOut_Inv(x: In3) = x -fun inOut_In(x: In3) = x -fun inOut_Out(x: In3) = x +fun inOut_In(x: In3<in Int>) = x +fun inOut_Out(x: In3<out Int>) = x fun inOut_Star(x: In3<*>) = x fun outInv_Inv(x: Out1) = x -fun outInv_In(x: Out1) = x +fun outInv_In(x: Out1<in Int>) = x fun outInv_Out(x: Out1) = x fun outInv_Star(x: Out1<*>) = x fun outIn_Inv(x: Out2) = x -fun outIn_In(x: Out2) = x -fun outIn_Out(x: Out2) = x +fun outIn_In(x: Out2<in Int>) = x +fun outIn_Out(x: Out2<out Int>) = x fun outIn_Star(x: Out2<*>) = x fun outOut_Inv(x: Out3) = x -fun outOut_In(x: Out3) = x +fun outOut_In(x: Out3<in Int>) = x fun outOut_Out(x: Out3) = x fun outOut_Star(x: Out3<*>) = x @@ -58,10 +58,10 @@ fun invInv_Star(x: Inv1<*>) = x fun invIn_Inv(x: Inv2) = x fun invIn_In(x: Inv2) = x -fun invIn_Out(x: Inv2) = x +fun invIn_Out(x: Inv2<out Int>) = x fun invIn_Star(x: Inv2<*>) = x fun invOut_Inv(x: Inv3) = x -fun invOut_In(x: Inv3) = x +fun invOut_In(x: Inv3<in Int>) = x fun invOut_Out(x: Inv3) = x fun invOut_Star(x: Inv3<*>) = x 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 c684d733e7c..5f3f1c00693 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 @@ -1193,6 +1193,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION) { firDiagnostic -> + ConflictingProjectionInTypealiasExpansionImpl( + firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED) { firDiagnostic -> VarianceOnTypeParameterNotAllowedImpl( firDiagnostic as FirPsiDiagnostic<*>, 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 93c6dd847a8..2b46411aa10 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 @@ -845,6 +845,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val type: KtType } + abstract class ConflictingProjectionInTypealiasExpansion : KtFirDiagnostic() { + override val diagnosticClass get() = ConflictingProjectionInTypealiasExpansion::class + abstract val type: KtType + } + abstract class VarianceOnTypeParameterNotAllowed : KtFirDiagnostic() { override val diagnosticClass get() = VarianceOnTypeParameterNotAllowed::class } 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 e4ee4dbb717..ecdec42eb22 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 @@ -1362,6 +1362,14 @@ internal class ConflictingProjectionImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class ConflictingProjectionInTypealiasExpansionImpl( + override val type: KtType, + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ConflictingProjectionInTypealiasExpansion(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class VarianceOnTypeParameterNotAllowedImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,