From a19994b8b6836b52603e5225c1fdb3912782f542 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Mon, 26 Feb 2024 15:08:48 +0200 Subject: [PATCH] [FIR] Rename `canHaveSubtypes()` and `lowerThanBound()` in K2 `lowerThanBound()` was renamed to: - draw attention to its corner cases - make its single usage less cryptic We may want to reserve the pretty name for a function that, for example, returns `true` if `argument` suits all the bounds. Similarly, `canHaveSubtypes()` does some questionable logic in case of `INVARIANTxINVARIANT`: some hypothetical `Inv` doesn't have subtypes so checking "Foo has subtypes strictly above Nothing || Foo has supertypes strictly below the parameter bounds" doesn't seem correct. `Foo` may have some, but `Inv` are not related to `Inv`. --- .../checkers/FirCastDiagnosticsHelpers.kt | 2 +- .../FirTypeParameterBoundsChecker.kt | 4 ++-- .../FirEqualityCompatibilityChecker.kt | 2 +- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 21 ++++++++++++------- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt index 1cfd7c64d9d..f7523283a99 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt @@ -135,7 +135,7 @@ private fun getCorrespondingKotlinClass(type: ConeSimpleKotlinType, session: Fir } private fun isFinal(type: ConeSimpleKotlinType, session: FirSession): Boolean { - return !type.canHaveSubtypes(session) + return !type.canHaveSubtypesAccordingToK1(session) } fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: CheckerContext): Boolean { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt index a86b8f95dc3..c50aab26413 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTypeParameterBoundsChecker.kt @@ -75,7 +75,7 @@ sealed class FirTypeParameterBoundsChecker(mppKind: MppCheckerKind) : FirTypePar if (containingDeclaration is FirProperty && containingDeclaration.isOverride) return declaration.symbol.resolvedBounds.forEach { bound -> - if (!bound.coneType.canHaveSubtypes(context.session)) { + if (!bound.coneType.canHaveSubtypesAccordingToK1(context.session)) { reporter.reportOn(bound.source, FirErrors.FINAL_UPPER_BOUND, bound.coneType, context) } } @@ -148,7 +148,7 @@ sealed class FirTypeParameterBoundsChecker(mppKind: MppCheckerKind) : FirTypePar fun anyConflictingTypes(types: List): Boolean { types.forEach { type -> - if (!type.canHaveSubtypes(context.session)) { + if (!type.canHaveSubtypesAccordingToK1(context.session)) { types.forEach { otherType -> if (type != otherType && !type.isRelated(context.session.typeContext, otherType)) { return true diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt index 2c4949004f2..27184d3860a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt @@ -333,7 +333,7 @@ private fun ConeKotlinType.toTypeInfo(session: FirSession): TypeInfo { isValueClass = bounds.any { it.toClassSymbol(session)?.isInline == true }, isFinal = bounds.any { it.toClassSymbol(session)?.isFinalClass == true }, // In K1's intersector, `canHaveSubtypes()` is called for `nullabilityStripped`. - withNullability(ConeNullability.NOT_NULL, session.typeContext).canHaveSubtypes(session), + withNullability(ConeNullability.NOT_NULL, session.typeContext).canHaveSubtypesAccordingToK1(session), ) } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index 057d060130f..85e0247f871 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -584,10 +584,13 @@ fun FirCallableDeclaration.isSubtypeOf( ) } +fun ConeKotlinType.canHaveSubtypesAccordingToK1(session: FirSession): Boolean = + hasSubtypesAboveNothingAccordingToK1(session) + /** * The original K1 function: [org.jetbrains.kotlin.types.TypeUtils.canHaveSubtypes]. */ -fun ConeKotlinType.canHaveSubtypes(session: FirSession): Boolean { +private fun ConeKotlinType.hasSubtypesAboveNothingAccordingToK1(session: FirSession): Boolean { if (this.isMarkedNullable) { return true } @@ -608,12 +611,13 @@ fun ConeKotlinType.canHaveSubtypes(session: FirSession): Boolean { val argument = typeProjection.type!! //safe because it is not a star val canHaveSubtypes = when (typeProjection.variance) { - Variance.OUT_VARIANCE -> argument.canHaveSubtypes(session) - Variance.IN_VARIANCE -> argument.lowerThanBound(typeParameterSymbol, session) + Variance.OUT_VARIANCE -> argument.hasSubtypesAboveNothingAccordingToK1(session) + Variance.IN_VARIANCE -> argument.hasSupertypesBelowParameterBoundsAccordingToK1(typeParameterSymbol, session) Variance.INVARIANT -> when (typeParameterSymbol.variance) { - Variance.OUT_VARIANCE -> argument.canHaveSubtypes(session) - Variance.IN_VARIANCE -> argument.lowerThanBound(typeParameterSymbol, session) - Variance.INVARIANT -> argument.canHaveSubtypes(session) || argument.lowerThanBound(typeParameterSymbol, session) + Variance.OUT_VARIANCE -> argument.hasSubtypesAboveNothingAccordingToK1(session) + Variance.IN_VARIANCE -> argument.hasSupertypesBelowParameterBoundsAccordingToK1(typeParameterSymbol, session) + Variance.INVARIANT -> argument.hasSubtypesAboveNothingAccordingToK1(session) + || argument.hasSupertypesBelowParameterBoundsAccordingToK1(typeParameterSymbol, session) } } @@ -646,7 +650,10 @@ fun ConeClassLikeType.toClassSymbol(session: FirSession): FirClassSymbol<*>? { * This function returns `true` if `argument` suits any bound rather than the * intersection of them all, and it expects there to be at least a single bound. */ -private fun ConeKotlinType.lowerThanBound(typeParameterSymbol: FirTypeParameterSymbol, session: FirSession): Boolean { +private fun ConeKotlinType.hasSupertypesBelowParameterBoundsAccordingToK1( + typeParameterSymbol: FirTypeParameterSymbol, + session: FirSession, +): Boolean { typeParameterSymbol.resolvedBounds.forEach { boundTypeRef -> if (this != boundTypeRef.coneType && isSubtypeOf(session.typeContext, boundTypeRef.coneType)) { return true