[FIR] Implement REDUNDANT_PROJECTION diagnostics, rename FirConflictingProjectionChecker -> FirProjectionRelationChecker, fix tests

This commit is contained in:
Ivan Kochurkin
2021-06-01 19:53:13 +03:00
committed by teamcityserver
parent 03e577bf98
commit f081a6b4fa
19 changed files with 98 additions and 98 deletions
@@ -7,12 +7,12 @@ fun a2(value: None<in Int>) {}
fun a3(value: None<out Int>) {}
fun a4(value: In<Int>) {}
fun a5(value: In<in Int>) {}
fun a5(value: In<<!REDUNDANT_PROJECTION!>in<!> Int>) {}
fun a6(value: In<<!CONFLICTING_PROJECTION!>out<!> Int>) {}
fun a7(value: Out<Int>) {}
fun a8(value: Out<<!CONFLICTING_PROJECTION!>in<!> Int>) {}
fun a9(value: Out<out Int>) {}
fun a9(value: Out<<!REDUNDANT_PROJECTION!>out<!> Int>) {}
typealias A1<K> = None<K>
typealias A2<K> = None<in K>
@@ -27,28 +27,28 @@ typealias A8<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = None<in K>
typealias A9<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = None<out K>
typealias A10<K> = In<K>
typealias A11<K> = In<in K>
typealias A11<K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
typealias A12<K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
typealias A13<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<K>
typealias A14<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<in K>
typealias A14<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
typealias A15<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
typealias A16<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<K>
typealias A17<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<in K>
typealias A17<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<<!REDUNDANT_PROJECTION!>in<!> K>
typealias A18<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = In<<!CONFLICTING_PROJECTION!>out<!> K>
typealias A19<K> = Out<K>
typealias A20<K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
typealias A21<K> = Out<out K>
typealias A21<K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
typealias A22<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<K>
typealias A23<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
typealias A24<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<out K>
typealias A24<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in<!> K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
typealias A25<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<K>
typealias A26<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<<!CONFLICTING_PROJECTION!>in<!> K>
typealias A27<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<out K>
typealias A27<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out<!> K> = Out<<!REDUNDANT_PROJECTION!>out<!> K>
class Outer<T> {
inner class Intermediate<K> {
@@ -82,16 +82,16 @@ class InOuter<in T> {
fun test10(): InOuter<Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test11(): InOuter<in Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test11(): InOuter<<!REDUNDANT_PROJECTION!>in<!> Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test12(): InOuter<<!CONFLICTING_PROJECTION!>out<!> Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test13(): InOuter<Int>.OutIntermediate<<!CONFLICTING_PROJECTION!>in<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test14(): InOuter<Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test14(): InOuter<Int>.OutIntermediate<<!REDUNDANT_PROJECTION!>out<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test15(): InOuter<Int>.OutIntermediate<String>.InInner<in Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test15(): InOuter<Int>.OutIntermediate<String>.InInner<<!REDUNDANT_PROJECTION!>in<!> Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test16(): InOuter<Int>.OutIntermediate<String>.InInner<<!CONFLICTING_PROJECTION!>out<!> Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test17(): InOuter<in Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test17(): InOuter<<!REDUNDANT_PROJECTION!>in<!> Int>.OutIntermediate<<!REDUNDANT_PROJECTION!>out<!> String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
fun test18(): InOuter<Int>.OutIntermediate<<!CONFLICTING_PROJECTION!>in<!> String>.InInner<<!CONFLICTING_PROJECTION!>out<!> Char> = InOuter<Int>().OutIntermediate<String>().InInner()
class TwoParametersOuter<T, in T1> {
@@ -4,7 +4,7 @@ interface List<out T : Any> {
infix fun concat(other: List<<!TYPE_VARIANCE_CONFLICT!>T<!>>): List<T>
}
typealias StringList = List<out String>
typealias StringList = List<<!REDUNDANT_PROJECTION!>out<!> String>
typealias AnyList = List<*>
abstract class AbstractList<out T : Any> : List<T>
@@ -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<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>out<!> A>) {
fun test_5(a: A, in1: In1<A>, in2: In1<<!REDUNDANT_PROJECTION!>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<<!CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION!>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<<!REDUNDANT_PROJECTION!>out<!> A>) {
out1.value().foo()
out2.<!UNRESOLVED_REFERENCE!>value<!>().foo()
out3.value().foo()
@@ -386,6 +386,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION by error<KtTypeParameter>(PositioningStrategy.VARIANCE_MODIFIER) {
parameter<ConeKotlinType>("type")
}
val REDUNDANT_PROJECTION by warning<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>()
@@ -276,6 +276,7 @@ object FirErrors {
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 REDUNDANT_PROJECTION by warning1<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>()
@@ -15,14 +15,13 @@ import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirDelegationInInterfac
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirFunctionTypeParametersSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirTypeParameterSyntaxChecker
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirReservedUnderscoreDeclarationChecker
import org.jetbrains.kotlin.fir.declarations.FirClass
object CommonDeclarationCheckers : DeclarationCheckers() {
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
get() = setOf(
FirModifierChecker,
FirConflictsChecker,
FirConflictingProjectionChecker,
FirProjectionRelationChecker,
FirTypeConstraintsChecker,
FirReservedUnderscoreDeclarationChecker
)
@@ -6,8 +6,8 @@
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.checkers.extractTypeRefAndSourceFromTypeArgument
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
object FirProjectionRelationChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirPropertyAccessor) {
return
@@ -62,16 +62,28 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
?.symbol?.fir
?.variance
if (
(fullyExpandedProjection is ConeKotlinTypeConflictingProjection ||
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE) &&
typeRef.source?.kind !is FirFakeSourceElementKind
val projectionRelation = if (fullyExpandedProjection is ConeKotlinTypeConflictingProjection ||
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE
) {
val typeArgSource = extractTypeArgumentSource(typeRef, it)
ProjectionRelation.Conflicting
} else if (actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.IN_VARIANCE ||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.OUT_VARIANCE
) {
ProjectionRelation.Redundant
} else {
ProjectionRelation.None
}
val (typeArgTypeRef, typeArgSource) = extractTypeRefAndSourceFromTypeArgument(typeRef, it) ?: continue
if (projectionRelation != ProjectionRelation.None && typeRef.source?.kind !is FirFakeSourceElementKind) {
reporter.reportOn(
typeArgSource ?: typeRef.source,
if (type != fullyExpandedType) FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION else FirErrors.CONFLICTING_PROJECTION,
typeArgSource ?: typeArgTypeRef.source,
if (projectionRelation == ProjectionRelation.Conflicting)
if (type != fullyExpandedType) FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION else FirErrors.CONFLICTING_PROJECTION
else
FirErrors.REDUNDANT_PROJECTION,
fullyExpandedType,
context
)
@@ -79,31 +91,9 @@ object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
}
}
private fun extractTypeArgumentSource(typeRef: FirTypeRef, index: Int): FirSourceElement? {
if (typeRef is FirResolvedTypeRef) {
val delegatedTypeRef = typeRef.delegatedTypeRef
if (delegatedTypeRef is FirUserTypeRef) {
var currentTypeArguments: List<FirTypeProjection>? = 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
private enum class ProjectionRelation {
Conflicting,
Redundant,
None
}
}
@@ -254,6 +254,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICI
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_OPEN_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_PROJECTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_RETURN_UNIT_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE
@@ -616,6 +617,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
"Conflicting projection in type alias expansion in intermediate type '{0}'",
RENDER_TYPE
)
map.put(
REDUNDANT_PROJECTION,
"Projection is redundant: the corresponding type parameter of {0} has the same variance",
RENDER_TYPE
)
map.put(
VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED,
"Variance annotations are only allowed for type parameters of classes and interfaces"