[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>
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)
in2.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()
out2.<!UNRESOLVED_REFERENCE!>value<!>().foo()
out3.value().foo()
@@ -383,6 +383,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CONFLICTING_PROJECTION by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) {
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 CATCH_PARAMETER_WITH_DEFAULT_VALUE by error<PsiElement>()
@@ -275,6 +275,7 @@ object FirErrors {
val ILLEGAL_PROJECTION_USAGE by error0<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<PsiElement>()
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 CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0<PsiElement>()
val REIFIED_TYPE_IN_CATCH_CLAUSE by error0<PsiElement>()
@@ -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<ConeClassLikeType>()
?.lookupTag
?.toSymbol(context.session)
?.fir.safeAs<FirRegularClass>()
?: return
private fun checkTypeRef(
typeRef: FirTypeRef,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
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)
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<FirTypeParameterRef>()
?.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
)
}
}
}
@@ -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"
@@ -9,8 +9,8 @@ typealias OutAlias<T> = Out<T>
typealias TestOutForIn<T> = In<<!CONFLICTING_PROJECTION!>out<!> T>
typealias TestInForOut<T> = Out<<!CONFLICTING_PROJECTION!>in<!> T>
typealias TestOutForInWithinAlias<T> = InAlias<out T>
typealias TestInForOutWithinAlias<T> = OutAlias<in T>
typealias TestOutForInWithinAlias<T> = InAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> T>
typealias TestInForOutWithinAlias<T> = OutAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> T>
fun <T> testOutForInWithinResolvedType(x: InAlias<out T>) {}
fun <T> testInForOutWithinResolvedType(x: OutAlias<in T>) {}
fun <T> testOutForInWithinResolvedType(x: InAlias<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> 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_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 inIn_Inv(x: In2<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 inOut_Inv(x: In3<Int>) = x
fun inOut_In(x: In3<in Int>) = x
fun inOut_Out(x: In3<out Int>) = x
fun inOut_In(x: In3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun inOut_Out(x: In3<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun inOut_Star(x: In3<*>) = 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_Star(x: Out1<*>) = x
fun outIn_Inv(x: Out2<Int>) = x
fun outIn_In(x: Out2<in Int>) = x
fun outIn_Out(x: Out2<out Int>) = x
fun outIn_In(x: Out2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>in<!> Int>) = x
fun outIn_Out(x: Out2<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> Int>) = x
fun outIn_Star(x: Out2<*>) = 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_Star(x: Out3<*>) = x
@@ -58,10 +58,10 @@ fun invInv_Star(x: Inv1<*>) = x
fun invIn_Inv(x: Inv2<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 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_Star(x: Inv3<*>) = x
@@ -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<*>,
@@ -845,6 +845,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val type: KtType
}
abstract class ConflictingProjectionInTypealiasExpansion : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = ConflictingProjectionInTypealiasExpansion::class
abstract val type: KtType
}
abstract class VarianceOnTypeParameterNotAllowed : KtFirDiagnostic<KtTypeParameter>() {
override val diagnosticClass get() = VarianceOnTypeParameterNotAllowed::class
}
@@ -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<KtTypeParameter> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class VarianceOnTypeParameterNotAllowedImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,