From ec20f527077e8440e748a5243c767bb3a0cefd93 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Thu, 17 Jun 2021 00:05:22 +0300 Subject: [PATCH] [FIR] Implement EXPANDED_TYPE_CANNOT_BE_INHERITED, PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE Add `starAsModifier` to `modifierSetPosition` --- .../diagnostics/FirDiagnosticsList.kt | 4 +++ .../fir/analysis/diagnostics/FirErrors.kt | 2 ++ .../fir/analysis/checkers/FirHelpers.kt | 6 ++-- .../declaration/FirSupertypesChecker.kt | 34 ++++++++++++++++--- .../diagnostics/FirDefaultErrorMessages.kt | 8 +++++ .../diagnostics/PositioningStrategies.kt | 20 ++++++++++- .../tests/ProjectionsInSupertypes.fir.kt | 2 +- ...assTypeAliasConstructorInSupertypes.fir.kt | 2 +- ...onstructorForProjectionInSupertypes.fir.kt | 16 --------- ...iasConstructorForProjectionInSupertypes.kt | 1 + ...AliasForProjectionInSuperInterfaces.fir.kt | 20 +++++------ .../diagnostics/KtFirDataClassConverters.kt | 13 +++++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 9 +++++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 15 ++++++++ .../checker/ProjectionsInSupertypes.fir.kt | 2 +- 15 files changed, 118 insertions(+), 36 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.fir.kt 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 305bb6b1869..058470f0584 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 @@ -136,6 +136,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("reason") } val CYCLIC_INHERITANCE_HIERARCHY by error() + val EXPANDED_TYPE_CANNOT_BE_INHERITED by error { + parameter("type") + } + val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error(PositioningStrategy.VARIANCE_MODIFIER) } val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") { 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 49e5eb4e84e..f41dc5d0149 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 @@ -144,6 +144,8 @@ object FirErrors { val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0() val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error1() val CYCLIC_INHERITANCE_HIERARCHY by error0() + val EXPANDED_TYPE_CANNOT_BE_INHERITED by error1() + val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0(SourceElementPositioningStrategies.VARIANCE_MODIFIER) // Constructor problems val CONSTRUCTOR_IN_OBJECT by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index b1d37e19e46..566dc2ad835 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -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 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypesChecker.kt index 721cbb3b6b0..1d480ad3c7c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypesChecker.kt @@ -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 + } + } + } + } } } } 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 5b43fec7baf..3b4b87d5dd9 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 @@ -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") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index d0afcd6c0b9..63290c9757f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -363,7 +363,7 @@ object PositioningStrategies { val LATEINIT_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.LATEINIT_KEYWORD) @JvmField - val VARIANCE_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD) + val VARIANCE_MODIFIER: PositioningStrategy = projectionPosition() @JvmField val CONST_MODIFIER: PositioningStrategy = 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 { + return object : PositioningStrategy() { + override fun mark(element: KtModifierListOwner): List { + 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 = object : PositioningStrategy() { override fun mark(element: KtArrayAccessExpression): List { diff --git a/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.fir.kt b/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.fir.kt index e87e1ec02e4..f956ad2959f 100644 --- a/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.fir.kt +++ b/compiler/testData/diagnostics/tests/ProjectionsInSupertypes.fir.kt @@ -3,4 +3,4 @@ interface B {} interface C {} interface D {} -interface Test : A, B, C<*>???, D {} +interface Test : A<in Int>, B<out Int>, C<*>???, D {} diff --git a/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.fir.kt b/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.fir.kt index 556d3a92904..1eb5305dbad 100644 --- a/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.fir.kt @@ -23,7 +23,7 @@ class Generic { inner class Test1 : GI() inner class Test2 : GIInt() inner class Test3 : GIStar() - inner class Test3a : test.Generic<*>.Inner() + inner class Test3a : test.Generic<*>.Inner() inner class Test4 : GG() inner class Test5 : GG() diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.fir.kt deleted file mode 100644 index 1f0cafbc552..00000000000 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -open class C - -typealias CStar = C<*> -typealias CIn = C -typealias COut = C -typealias CT = C - -class Test1 : CStar() -class Test2 : CIn() -class Test3 : COut() - -class Test4 : CStar { - constructor() : super() -} - -class Test5 : CT<*>() diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt index 9a6c654bfff..fa0b08f148f 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL open class C typealias CStar = C<*> diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.fir.kt index 95c4d4badec..6d85f45a6b1 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasForProjectionInSuperInterfaces.fir.kt @@ -15,18 +15,18 @@ typealias InStar = In<*> typealias InIn = In<in Int> typealias InT = In -class Test1 : InvStar -class Test2 : InvIn -class Test3 : InvOut -class Test4 : InvT<*> +class Test1 : InvStar +class Test2 : InvIn +class Test3 : InvOut +class Test4 : InvT<*> class Test5 : InvT> -class Test6 : OutStar -class Test7 : OutOut +class Test6 : OutStar +class Test7 : OutOut class Test8 : OutT -class Test9 : OutT<out Int> +class Test9 : OutT<out Int> -class Test10 : InStar -class Test11 : InIn +class Test10 : InStar +class Test11 : InIn class Test12 : InT -class Test13 : InT<in Int> +class Test13 : InT<in Int> 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 de135d28c56..70b84fd9950 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 @@ -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, 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 2208aadb390..ed7c8c5bf0a 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 @@ -307,6 +307,15 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = CyclicInheritanceHierarchy::class } + abstract class ExpandedTypeCannotBeInherited : KtFirDiagnostic() { + override val diagnosticClass get() = ExpandedTypeCannotBeInherited::class + abstract val type: KtType + } + + abstract class ProjectionInImmediateArgumentToSupertype : KtFirDiagnostic() { + override val diagnosticClass get() = ProjectionInImmediateArgumentToSupertype::class + } + abstract class ConstructorInObject : KtFirDiagnostic() { override val diagnosticClass get() = ConstructorInObject::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 c141f3933d0..5cda196cd7a 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 @@ -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 { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ProjectionInImmediateArgumentToSupertypeImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ProjectionInImmediateArgumentToSupertype(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ConstructorInObjectImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken, diff --git a/idea/testData/checker/ProjectionsInSupertypes.fir.kt b/idea/testData/checker/ProjectionsInSupertypes.fir.kt index bf594fc8312..4cf4e534c1f 100644 --- a/idea/testData/checker/ProjectionsInSupertypes.fir.kt +++ b/idea/testData/checker/ProjectionsInSupertypes.fir.kt @@ -3,4 +3,4 @@ interface B {} interface C {} interface D {} -interface Test : A, B, C<*>???, D {} +interface Test : A<in Int>, B<out Int>, C<*>???, D {}