[FIR] Implement EXPANDED_TYPE_CANNOT_BE_INHERITED, PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE

Add `starAsModifier` to `modifierSetPosition`
This commit is contained in:
Ivan Kochurkin
2021-06-17 00:05:22 +03:00
committed by teamcityserver
parent 937846b62d
commit ec20f52707
15 changed files with 118 additions and 36 deletions
@@ -136,6 +136,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<String>("reason")
}
val CYCLIC_INHERITANCE_HIERARCHY by error<PsiElement>()
val EXPANDED_TYPE_CANNOT_BE_INHERITED by error<KtTypeReference> {
parameter<ConeKotlinType>("type")
}
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error<KtModifierListOwner>(PositioningStrategy.VARIANCE_MODIFIER)
}
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
@@ -144,6 +144,8 @@ object FirErrors {
val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0<KtTypeReference>()
val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error1<KtElement, String>()
val CYCLIC_INHERITANCE_HIERARCHY by error0<PsiElement>()
val EXPANDED_TYPE_CANNOT_BE_INHERITED by error1<KtTypeReference, ConeKotlinType>()
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
// Constructor problems
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -521,6 +521,8 @@ private val FirSimpleFunction.matchesHashCodeSignature: Boolean
private val FirSimpleFunction.matchesToStringSignature: Boolean
get() = valueParameters.isEmpty()
val ConeTypeProjection.isConflictingOrNotInvariant: Boolean get() = kind != ProjectionKind.INVARIANT || this is ConeKotlinTypeConflictingProjection
fun checkTypeMismatch(
lValueOriginalType: ConeKotlinType,
rValue: FirExpression,
@@ -600,8 +602,8 @@ fun extractArgumentTypeRefAndSource(typeRef: FirTypeRef?, index: Int): FirTypeRe
}
val typeArgument = currentTypeArguments?.elementAtOrNull(currentIndex)
if (typeArgument is FirTypeProjectionWithVariance) {
return FirTypeRefSource(typeArgument.typeRef, typeArgument.source)
if (typeArgument is FirTypeProjection) {
return FirTypeRefSource((typeArgument as? FirTypeProjectionWithVariance)?.typeRef, typeArgument.source)
}
} else if (delegatedTypeRef is FirFunctionTypeRef) {
val valueParameters = delegatedTypeRef.valueParameters
@@ -7,7 +7,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.analysis.checkers.*
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
@@ -15,12 +17,11 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.modality
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isExtensionFunctionType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object FirSupertypesChecker : FirClassChecker() {
@@ -80,6 +81,31 @@ object FirSupertypesChecker : FirClassChecker() {
}
}
}
val fullyExpandedType = coneType.fullyExpandedType(context.session)
val symbol = fullyExpandedType.toSymbol(context.session)
if (coneType.typeArguments.isNotEmpty()) {
for ((index, typeArgument) in coneType.typeArguments.withIndex()) {
if (typeArgument.isConflictingOrNotInvariant) {
val (_, argSource) = extractArgumentTypeRefAndSource(superTypeRef, index) ?: continue
reporter.reportOn(
argSource ?: superTypeRef.source,
FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE,
context
)
}
}
} else {
if (symbol is FirRegularClassSymbol && symbol.fir.classKind == ClassKind.INTERFACE) {
for (typeArgument in fullyExpandedType.typeArguments) {
if (typeArgument.isConflictingOrNotInvariant) {
reporter.reportOn(superTypeRef.source, FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED, coneType, context)
break
}
}
}
}
}
}
}
@@ -113,6 +113,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DECLARATION_WITH_BODY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DELEGATED_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_LATEINIT_PROPERTY
@@ -250,6 +251,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_FUNCTION_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_PROPERTY_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD
@@ -458,6 +460,12 @@ class FirDefaultErrorMessages {
map.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class")
map.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Supertype is not a class or interface", TO_STRING)
map.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type")
map.put(
EXPANDED_TYPE_CANNOT_BE_INHERITED,
"Type alias expands to {0}, which is not a class, an interface, or an object",
RENDER_TYPE
)
map.put(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, "Projections are not allowed for immediate arguments of a supertype")
// Constructor problems
map.put(CONSTRUCTOR_IN_OBJECT, "Constructors are not allowed for objects")
@@ -363,7 +363,7 @@ object PositioningStrategies {
val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
@JvmField
val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = projectionPosition()
@JvmField
val CONST_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.CONST_KEYWORD)
@@ -414,11 +414,29 @@ object PositioningStrategies {
return markElement(modifier)
}
}
throw IllegalStateException("None of the modifiers is found: " + listOf(*tokens))
}
}
}
@JvmStatic
fun projectionPosition(): PositioningStrategy<KtModifierListOwner> {
return object : PositioningStrategy<KtModifierListOwner>() {
override fun mark(element: KtModifierListOwner): List<TextRange> {
if (element is KtTypeProjection && element.projectionKind == KtProjectionKind.STAR) {
return markElement(element)
}
val modifierList = element.modifierList.sure { "No modifier list, but modifier has been found by the analyzer" }
modifierList.getModifier(KtTokens.IN_KEYWORD)?.let { return markElement(it) }
modifierList.getModifier(KtTokens.OUT_KEYWORD)?.let { return markElement(it) }
throw IllegalStateException("None of the modifiers is found: in, out")
}
}
}
@JvmField
val ARRAY_ACCESS: PositioningStrategy<KtArrayAccessExpression> = object : PositioningStrategy<KtArrayAccessExpression>() {
override fun mark(element: KtArrayAccessExpression): List<TextRange> {
@@ -3,4 +3,4 @@ interface B<T> {}
interface C<T> {}
interface D<T> {}
interface Test : A<in Int>, B<out Int>, C<*>??<!NULLABLE_SUPERTYPE!>?<!>, D<Int> {}
interface Test : A<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>in<!> Int>, B<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>out<!> Int>, C<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>??<!NULLABLE_SUPERTYPE!>?<!>, D<Int> {}
@@ -23,7 +23,7 @@ class Generic<T1> {
inner class Test1 : GI<T1>()
inner class Test2 : <!UNRESOLVED_REFERENCE!>GIInt<!>()
inner class Test3 : GIStar()
inner class Test3a : test.Generic<*>.Inner()
inner class Test3a : test.Generic<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>.Inner()
inner class Test4<T2> : GG<T1, T2>()
inner class Test5 : GG<T1, Int>()
@@ -1,16 +0,0 @@
open class C<T>
typealias CStar = C<*>
typealias CIn = C<in Int>
typealias COut = C<out Int>
typealias CT<T> = C<T>
class Test1 : CStar()
class Test2 : CIn()
class Test3 : COut()
class Test4 : CStar {
constructor() : super()
}
class Test5 : CT<*>()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
open class C<T>
typealias CStar = C<*>
@@ -15,18 +15,18 @@ typealias InStar = In<*>
typealias InIn = In<<!REDUNDANT_PROJECTION!>in<!> Int>
typealias InT<T> = In<T>
class Test1 : InvStar
class Test2 : InvIn
class Test3 : InvOut
class Test4 : InvT<*>
class Test1 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>InvStar<!>
class Test2 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>InvIn<!>
class Test3 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>InvOut<!>
class Test4 : InvT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>
class Test5 : InvT<InvT<*>>
class Test6 : OutStar
class Test7 : OutOut
class Test6 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>OutStar<!>
class Test7 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>OutOut<!>
class Test8 : OutT<Int>
class Test9 : OutT<<!REDUNDANT_PROJECTION!>out<!> Int>
class Test9 : OutT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, REDUNDANT_PROJECTION!>out<!> Int>
class Test10 : InStar
class Test11 : InIn
class Test10 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>InStar<!>
class Test11 : <!EXPANDED_TYPE_CANNOT_BE_INHERITED!>InIn<!>
class Test12 : InT<Int>
class Test13 : InT<<!REDUNDANT_PROJECTION!>in<!> Int>
class Test13 : InT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, REDUNDANT_PROJECTION!>in<!> Int>
@@ -412,6 +412,19 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED) { firDiagnostic ->
ExpandedTypeCannotBeInheritedImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE) { firDiagnostic ->
ProjectionInImmediateArgumentToSupertypeImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.CONSTRUCTOR_IN_OBJECT) { firDiagnostic ->
ConstructorInObjectImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -307,6 +307,15 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = CyclicInheritanceHierarchy::class
}
abstract class ExpandedTypeCannotBeInherited : KtFirDiagnostic<KtTypeReference>() {
override val diagnosticClass get() = ExpandedTypeCannotBeInherited::class
abstract val type: KtType
}
abstract class ProjectionInImmediateArgumentToSupertype : KtFirDiagnostic<KtModifierListOwner>() {
override val diagnosticClass get() = ProjectionInImmediateArgumentToSupertype::class
}
abstract class ConstructorInObject : KtFirDiagnostic<KtDeclaration>() {
override val diagnosticClass get() = ConstructorInObject::class
}
@@ -479,6 +479,21 @@ internal class CyclicInheritanceHierarchyImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExpandedTypeCannotBeInheritedImpl(
override val type: KtType,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ExpandedTypeCannotBeInherited(), KtAbstractFirDiagnostic<KtTypeReference> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ProjectionInImmediateArgumentToSupertypeImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ProjectionInImmediateArgumentToSupertype(), KtAbstractFirDiagnostic<KtModifierListOwner> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ConstructorInObjectImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
+1 -1
View File
@@ -3,4 +3,4 @@ interface B<T> {}
interface C<T> {}
interface D<T> {}
interface Test : A<in Int>, B<out Int>, C<*>??<error descr="[NULLABLE_SUPERTYPE] A supertype cannot be nullable">?</error>, D<Int> {}
interface Test : A<<error descr="[PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE] Projections are not allowed for immediate arguments of a supertype">in</error> Int>, B<<error descr="[PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE] Projections are not allowed for immediate arguments of a supertype">out</error> Int>, C<<error descr="[PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE] Projections are not allowed for immediate arguments of a supertype">*</error>>??<error descr="[NULLABLE_SUPERTYPE] A supertype cannot be nullable">?</error>, D<Int> {}