[FIR] Implement CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-06-01 16:22:02 +03:00
committed by teamcityserver
parent ca970f0a8b
commit 03e577bf98
10 changed files with 67 additions and 31 deletions
@@ -71,13 +71,13 @@ typealias Out1<X> = Out<X>
typealias Invariant1<X> = Invariant<X> typealias Invariant1<X> = Invariant<X>
fun test_5(a: A, in1: In1<A>, in2: In1<in A>, in3: In1<out A>) { fun test_5(a: A, in1: In1<A>, in2: In1<in A>, in3: In1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> A>) {
in1.take(a) in1.take(a)
in2.take(a) in2.take(a)
in3.<!UNRESOLVED_REFERENCE!>take<!>(a) in3.<!UNRESOLVED_REFERENCE!>take<!>(a)
} }
fun test_6(a: A, out1: Out1<A>, out2: Out1<in A>, out3: Out1<out A>) { fun test_6(a: A, out1: Out1<A>, out2: Out1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> A>, out3: Out1<out A>) {
out1.value().foo() out1.value().foo()
out2.<!UNRESOLVED_REFERENCE!>value<!>().foo() out2.<!UNRESOLVED_REFERENCE!>value<!>().foo()
out3.value().foo() out3.value().foo()
@@ -383,6 +383,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CONFLICTING_PROJECTION by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) { val CONFLICTING_PROJECTION by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) {
parameter<ConeKotlinType>("type") parameter<ConeKotlinType>("type")
} }
val CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) {
parameter<ConeKotlinType>("type")
}
val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER)
val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error<PsiElement>() val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error<PsiElement>()
@@ -275,6 +275,7 @@ object FirErrors {
val ILLEGAL_PROJECTION_USAGE by error0<PsiElement>() val ILLEGAL_PROJECTION_USAGE by error0<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<PsiElement>() val TYPE_PARAMETERS_IN_ENUM by error0<PsiElement>()
val CONFLICTING_PROJECTION by error1<KtTypeParameter, ConeKotlinType>(SourceElementPositioningStrategies.VARIANCE_MODIFIER) val CONFLICTING_PROJECTION by error1<KtTypeParameter, ConeKotlinType>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
val CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION by error1<KtTypeParameter, ConeKotlinType>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error0<KtTypeParameter>(SourceElementPositioningStrategies.VARIANCE_MODIFIER) val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error0<KtTypeParameter>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0<PsiElement>() val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0<PsiElement>()
val REIFIED_TYPE_IN_CATCH_CLAUSE by error0<PsiElement>() val REIFIED_TYPE_IN_CATCH_CLAUSE by error0<PsiElement>()
@@ -5,13 +5,14 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration 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.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.* 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.fir.types.*
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -41,34 +42,39 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
} }
} }
private fun checkTypeRef(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { private fun checkTypeRef(
val declaration = typeRef.coneTypeSafe<ConeClassLikeType>() typeRef: FirTypeRef,
?.lookupTag context: CheckerContext,
?.toSymbol(context.session) reporter: DiagnosticReporter,
?.fir.safeAs<FirRegularClass>() ) {
?: return val type = typeRef.coneTypeSafe<ConeClassLikeType>()
val fullyExpandedType = type?.fullyExpandedType(context.session) ?: return
val declaration = fullyExpandedType.toSymbol(context.session)?.fir.safeAs<FirRegularClass>() ?: return
val size = minOf(declaration.typeParameters.size, typeRef.coneType.typeArguments.size) val size = minOf(declaration.typeParameters.size, typeRef.coneType.typeArguments.size)
for (it in 0 until size) { for (it in 0 until size) {
val proto = declaration.typeParameters[it] val proto = declaration.typeParameters[it]
val actual = typeRef.coneType.typeArguments[it] val actual = typeRef.coneType.typeArguments[it]
val fullyExpandedProjection = fullyExpandedType.typeArguments[it]
val protoVariance = proto.safeAs<FirTypeParameterRef>() val protoVariance = proto.safeAs<FirTypeParameterRef>()
?.symbol?.fir ?.symbol?.fir
?.variance ?.variance
?: continue
if (protoVariance == Variance.INVARIANT) {
continue
}
if ( if (
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE || (fullyExpandedProjection is ConeKotlinTypeConflictingProjection ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE) &&
typeRef.source?.kind !is FirFakeSourceElementKind
) { ) {
val typeArgSource = extractTypeArgumentSource(typeRef, it) 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
)
} }
} }
} }
@@ -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.CONDITION_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS 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
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.CONFLICTING_UPPER_BOUNDS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT 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 ''*''", "Projection is conflicting with variance of the corresponding type parameter of {0}. Remove the projection or replace it with ''*''",
RENDER_TYPE RENDER_TYPE
) )
map.put(
CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION,
"Conflicting projection in type alias expansion in intermediate type '{0}'",
RENDER_TYPE
)
map.put( map.put(
VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED,
"Variance annotations are only allowed for type parameters of classes and interfaces" "Variance annotations are only allowed for type parameters of classes and interfaces"
@@ -9,8 +9,8 @@ typealias OutAlias<T> = Out<T>
typealias TestOutForIn<T> = In<<!CONFLICTING_PROJECTION!>out<!> T> typealias TestOutForIn<T> = In<<!CONFLICTING_PROJECTION!>out<!> T>
typealias TestInForOut<T> = Out<<!CONFLICTING_PROJECTION!>in<!> T> typealias TestInForOut<T> = Out<<!CONFLICTING_PROJECTION!>in<!> T>
typealias TestOutForInWithinAlias<T> = InAlias<out T> typealias TestOutForInWithinAlias<T> = InAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> T>
typealias TestInForOutWithinAlias<T> = OutAlias<in T> typealias TestInForOutWithinAlias<T> = OutAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> T>
fun <T> testOutForInWithinResolvedType(x: InAlias<out T>) {} fun <T> testOutForInWithinResolvedType(x: InAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> T>) {}
fun <T> testInForOutWithinResolvedType(x: OutAlias<in T>) {} fun <T> testInForOutWithinResolvedType(x: OutAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> T>) {}
@@ -23,31 +23,31 @@ val inv1: Inv1<Int> = Inv<Int>()
fun inInv_Inv(x: In1<Int>) = x fun inInv_Inv(x: In1<Int>) = x
fun inInv_In(x: In1<in Int>) = x fun inInv_In(x: In1<in Int>) = x
fun inInv_Out(x: In1<out Int>) = x fun inInv_Out(x: In1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun inInv_Star(x: In1<*>) = x fun inInv_Star(x: In1<*>) = x
fun inIn_Inv(x: In2<Int>) = x fun inIn_Inv(x: In2<Int>) = x
fun inIn_In(x: In2<in Int>) = x fun inIn_In(x: In2<in Int>) = x
fun inIn_Out(x: In2<out Int>) = x fun inIn_Out(x: In2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun inIn_Star(x: In2<*>) = x fun inIn_Star(x: In2<*>) = x
fun inOut_Inv(x: In3<Int>) = x fun inOut_Inv(x: In3<Int>) = x
fun inOut_In(x: In3<in Int>) = x fun inOut_In(x: In3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun inOut_Out(x: In3<out Int>) = x fun inOut_Out(x: In3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun inOut_Star(x: In3<*>) = x fun inOut_Star(x: In3<*>) = x
fun outInv_Inv(x: Out1<Int>) = x fun outInv_Inv(x: Out1<Int>) = x
fun outInv_In(x: Out1<in Int>) = x fun outInv_In(x: Out1<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun outInv_Out(x: Out1<out Int>) = x fun outInv_Out(x: Out1<out Int>) = x
fun outInv_Star(x: Out1<*>) = x fun outInv_Star(x: Out1<*>) = x
fun outIn_Inv(x: Out2<Int>) = x fun outIn_Inv(x: Out2<Int>) = x
fun outIn_In(x: Out2<in Int>) = x fun outIn_In(x: Out2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun outIn_Out(x: Out2<out Int>) = x fun outIn_Out(x: Out2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun outIn_Star(x: Out2<*>) = x fun outIn_Star(x: Out2<*>) = x
fun outOut_Inv(x: Out3<Int>) = x fun outOut_Inv(x: Out3<Int>) = x
fun outOut_In(x: Out3<in Int>) = x fun outOut_In(x: Out3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun outOut_Out(x: Out3<out Int>) = x fun outOut_Out(x: Out3<out Int>) = x
fun outOut_Star(x: Out3<*>) = x fun outOut_Star(x: Out3<*>) = x
@@ -58,10 +58,10 @@ fun invInv_Star(x: Inv1<*>) = x
fun invIn_Inv(x: Inv2<Int>) = x fun invIn_Inv(x: Inv2<Int>) = x
fun invIn_In(x: Inv2<in Int>) = x fun invIn_In(x: Inv2<in Int>) = x
fun invIn_Out(x: Inv2<out Int>) = x fun invIn_Out(x: Inv2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun invIn_Star(x: Inv2<*>) = x fun invIn_Star(x: Inv2<*>) = x
fun invOut_Inv(x: Inv3<Int>) = x fun invOut_Inv(x: Inv3<Int>) = x
fun invOut_In(x: Inv3<in Int>) = x fun invOut_In(x: Inv3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun invOut_Out(x: Inv3<out Int>) = x fun invOut_Out(x: Inv3<out Int>) = x
fun invOut_Star(x: Inv3<*>) = x fun invOut_Star(x: Inv3<*>) = x
@@ -1193,6 +1193,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, 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 -> add(FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED) { firDiagnostic ->
VarianceOnTypeParameterNotAllowedImpl( VarianceOnTypeParameterNotAllowedImpl(
firDiagnostic as FirPsiDiagnostic<*>, firDiagnostic as FirPsiDiagnostic<*>,
@@ -845,6 +845,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val type: KtType abstract val type: KtType
} }
abstract class ConflictingProjectionInTypealiasExpansion : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = ConflictingProjectionInTypealiasExpansion::class
abstract val type: KtType
}
abstract class VarianceOnTypeParameterNotAllowed : KtFirDiagnostic<KtTypeParameter>() { abstract class VarianceOnTypeParameterNotAllowed : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = VarianceOnTypeParameterNotAllowed::class override val diagnosticClass get() = VarianceOnTypeParameterNotAllowed::class
} }
@@ -1362,6 +1362,14 @@ internal class ConflictingProjectionImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class ConflictingProjectionInTypealiasExpansionImpl(
override val type: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ConflictingProjectionInTypealiasExpansion(), KtAbstractFirDiagnostic<KtTypeParameter> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class VarianceOnTypeParameterNotAllowedImpl( internal class VarianceOnTypeParameterNotAllowedImpl(
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken, override val token: ValidityToken,