diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt index 1fc93beebe0..30e4c2c4bcc 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/FirReferenceResolveHelper.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.providers.toSymbol import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.toSymbol @@ -261,7 +262,7 @@ internal object FirReferenceResolveHelper { return buildList { scope.processFunctionsByName(OperatorNameConventions.EQUALS) { functionSymbol -> val parameterSymbol = functionSymbol.valueParameterSymbols.singleOrNull() - if (parameterSymbol != null && parameterSymbol.fir.returnTypeRef.isNullableAny) { + if (parameterSymbol != null && parameterSymbol.fir.returnTypeRef.coneType.fullyExpandedType(session).isNullableAny) { add(functionSymbol.buildSymbol(symbolBuilder)) } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt index 900e7a01b2c..ce96db35804 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.isNullableAny import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols +import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck /** * [KtFirTypeParameterSymbolBase] provides shared implementations for [KtFirTypeParameterSymbol] and [KtFirPsiJavaTypeParameterSymbol]. @@ -29,6 +30,7 @@ internal sealed class KtFirTypeParameterSymbolBase : KtTypeParameterSymbol(), Kt KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token) } + @OptIn(UnexpandedTypeCheck::class) override val upperBounds: List by cached { firSymbol.resolvedBounds.mapNotNull { type -> if (type.isNullableAny) return@mapNotNull null diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt index b96d211a213..7fda3f12355 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/FirKotlinToJvmBytecodeCompiler.kt @@ -40,7 +40,6 @@ import org.jetbrains.kotlin.fir.types.isArrayType import org.jetbrains.kotlin.fir.types.isString import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler -import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.modules.Module import org.jetbrains.kotlin.modules.TargetId diff --git a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt index a9a82203769..7de0df3fca3 100644 --- a/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt +++ b/compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/jvm/checkers/declaration/FirRepeatableAnnotationChecker.kt @@ -165,7 +165,7 @@ object FirRepeatableAnnotationChecker : FirBasicDeclarationChecker() { val valueParameterSymbols = containerCtor.valueParameterSymbols val parameterName = StandardClassIds.Annotations.ParameterNames.value val value = valueParameterSymbols.find { it.name == parameterName } - if (value == null || !value.resolvedReturnTypeRef.isArrayType || + if (value == null || !value.resolvedReturnTypeRef.coneType.fullyExpandedType(context.session).isArrayType || value.resolvedReturnTypeRef.type.typeArguments.single().type != annotationClass.defaultType() ) { reporter.reportOn( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt index e93b9c9ab0b..0f5c913d8e7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMethodOfAnyImplementedInInterfaceChecker.kt @@ -13,10 +13,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction +import org.jetbrains.kotlin.fir.declarations.isEquals import org.jetbrains.kotlin.fir.declarations.utils.hasBody import org.jetbrains.kotlin.fir.declarations.utils.isInterface import org.jetbrains.kotlin.fir.declarations.utils.isOverride -import org.jetbrains.kotlin.fir.symbols.impl.isEquals import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING @@ -43,7 +43,7 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirRegularClassChecker(), F (function.name == HASHCODE_NAME || function.name == TO_STRING) ) { methodOfAny = true - } else if (function.isEquals()) { + } else if (function.isEquals(context.session)) { methodOfAny = true } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt index 5d11c4982fb..8dd465120af 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirValueClassDeclarationChecker.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol -import org.jetbrains.kotlin.fir.symbols.impl.isEquals import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef import org.jetbrains.kotlin.lexer.KtTokens @@ -192,7 +191,7 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() { ) } - primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() -> { + primaryConstructorParameter.returnTypeRef.isInapplicableParameterType(context.session) -> { reporter.reportOn( primaryConstructorParameter.returnTypeRef.source, FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, @@ -227,7 +226,7 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() { if (it !is FirSimpleFunction) { return@forEach } - if (it.isEquals()) equalsFromAnyOverriding = it + if (it.isEquals(context.session)) equalsFromAnyOverriding = it if (it.isTypedEqualsInValueClass(context.session)) typedEquals = it } equalsFromAnyOverriding to typedEquals @@ -268,8 +267,8 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() { return isVararg || !primaryConstructorProperty.isVal || isOpen } - private fun FirTypeRef.isInapplicableParameterType() = - isUnit || isNothing + private fun FirTypeRef.isInapplicableParameterType(session: FirSession): Boolean = + coneType.fullyExpandedType(session).let { it.isUnit || it.isNothing } private fun ConeKotlinType.isGenericArrayOfTypeParameter(): Boolean { if (this.typeArguments.firstOrNull() is ConeStarProjection || !isPotentiallyArray()) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNamedVarargChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNamedVarargChecker.kt index ed9c08136a8..9ba5babb6b8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNamedVarargChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNamedVarargChecker.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirErrorTypeRef +import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isArrayType @@ -50,6 +51,8 @@ object FirNamedVarargChecker : FirCallChecker() { val typeRef = argument.expression.typeRef if (typeRef is FirErrorTypeRef) return if (argument.expression is FirArrayOfCall) return + + @OptIn(UnexpandedTypeCheck::class) if (allowAssignArray && typeRef.isArrayType) return if (isAnnotation) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotNullAssertionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotNullAssertionChecker.kt index 14982b331b2..1e918086ba6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotNullAssertionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirNotNullAssertionChecker.kt @@ -30,6 +30,7 @@ object FirNotNullAssertionChecker : FirCheckNotNullCallChecker() { } // TODO: use of Unit is subject to change. // See BodyResolveComponents.typeForQualifier in ResolveUtils.kt which returns Unit for no value type. + @OptIn(UnexpandedTypeCheck::class) if (argument is FirResolvedQualifier && argument.typeRef.isUnit) { // Would be reported as NO_COMPANION_OBJECT return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt index 556ecd092a5..361ff4c72fa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirStandaloneQualifierChecker.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck import org.jetbrains.kotlin.fir.types.isUnit object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() { @@ -26,8 +27,11 @@ object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() { if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return val lastGetClass = context.getClassCalls.lastOrNull() if (lastGetClass?.argument === expression) return - // Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below + + // Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below in reportErrorOn + @OptIn(UnexpandedTypeCheck::class) if (!expression.typeRef.isUnit) return + expression.symbol.reportErrorOn(expression.source, context, reporter) } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantReturnUnitType.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantReturnUnitType.kt index 3a3c42b215e..7083ff5526c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantReturnUnitType.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantReturnUnitType.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isUnit object RedundantReturnUnitType : FirSimpleFunctionChecker() { @@ -23,7 +25,7 @@ object RedundantReturnUnitType : FirSimpleFunctionChecker() { if (declaration.source?.kind is KtFakeSourceElementKind) return if (returnType.annotations.isNotEmpty()) return - if (returnType.isUnit) { + if (returnType.coneType.fullyExpandedType(context.session).isUnit) { reporter.reportOn(declaration.returnTypeRef.source, FirErrors.REDUNDANT_RETURN_UNIT_TYPE, context) } } diff --git a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt index aeba10983df..2ba557861ac 100644 --- a/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt +++ b/compiler/fir/cones/src/org/jetbrains/kotlin/fir/types/ConeBuiltinTypeUtils.kt @@ -45,7 +45,8 @@ val ConeKotlinType.isPrimitiveNumberOrNullableType: Boolean val ConeKotlinType.isArrayType: Boolean get() { return isBuiltinType(StandardClassIds.Array, false) || - StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } + StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } || + StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, false) } } // Same as [KotlinBuiltIns#isNonPrimitiveArray] diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt index d02a1a4d98e..62c1d2312d2 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirContractDeserializer.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck import org.jetbrains.kotlin.fir.types.isBoolean import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.isInstanceType @@ -37,7 +38,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) : override fun extractVariable( valueParameterIndex: Int, owner: FirContractDescriptionOwner - ): KtValueParameterReference? { + ): KtValueParameterReference? { val name: String val ownerFunction = owner as FirSimpleFunction val typeRef = if (valueParameterIndex < 0) { @@ -49,6 +50,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) : parameter.returnTypeRef } ?: return null + @OptIn(UnexpandedTypeCheck::class) return if (!typeRef.isBoolean) KtValueParameterReference(valueParameterIndex, name) else diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt index 0611613bfff..241cb94b8f0 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/constant/FirToConstantValueTransformer.kt @@ -196,8 +196,8 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor? { - if (functionCall.isArrayOfCall) { - return FirArrayOfCallTransformer().transformFunctionCall(functionCall, null).accept(this, data) + if (functionCall.isArrayOfCall(data.session)) { + return FirArrayOfCallTransformer().transformFunctionCall(functionCall, data.session).accept(this, data) } return visitQualifiedAccessExpression(functionCall, data) } @@ -289,7 +289,7 @@ internal object FirToConstantValueChecker : FirDefaultVisitor it.valueParameters.lastOrNull()?.let { param -> param.defaultValue == null && !param.isVararg } == true @@ -161,9 +162,9 @@ private abstract class Check { } private object Checks { - fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check() { + fun simple(message: String, predicate: (FirSimpleFunction, FirSession) -> Boolean) = object : Check() { override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? = - message.takeIf { !predicate(function) } + message.takeIf { !predicate(function, session) } } fun full(message: String, predicate: (FirSession, FirSimpleFunction) -> Boolean) = object : Check() { @@ -171,51 +172,51 @@ private object Checks { message.takeIf { !predicate(session, function) } } - val memberOrExtension = simple("must be a member or an extension function") { + val memberOrExtension = simple("must be a member or an extension function") { it, _ -> it.dispatchReceiverType != null || it.receiverParameter != null } - val member = simple("must be a member function") { + val member = simple("must be a member function") { it, _ -> it.dispatchReceiverType != null } - val nonSuspend = simple("must not be suspend") { + val nonSuspend = simple("must not be suspend") { it, _ -> !it.isSuspend } object ValueParametersCount { - fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) { + fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) { it, _ -> it.valueParameters.size >= n } - fun exactly(n: Int) = simple("must have exactly $n value parameters") { + fun exactly(n: Int) = simple("must have exactly $n value parameters") { it, _ -> it.valueParameters.size == n } - val single = simple("must have a single value parameter") { + val single = simple("must have a single value parameter") { it, _ -> it.valueParameters.size == 1 } - val none = simple("must have no value parameters") { + val none = simple("must have no value parameters") { it, _ -> it.valueParameters.isEmpty() } } object Returns { - val boolean = simple("must return Boolean") { - it.returnTypeRef.isBoolean + val boolean = simple("must return Boolean") { it, session -> + it.returnTypeRef.coneType.fullyExpandedType(session).isBoolean } - val int = simple("must return Int") { - it.returnTypeRef.isInt + val int = simple("must return Int") { it, session -> + it.returnTypeRef.coneType.fullyExpandedType(session).isInt } - val unit = simple("must return Unit") { - it.returnTypeRef.isUnit + val unit = simple("must return Unit") { it, session -> + it.returnTypeRef.coneType.fullyExpandedType(session).isUnit } } - val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") { + val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") { it, _ -> it.valueParameters.all { param -> param.defaultValue == null && !param.isVararg } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt index b67cbb615ba..2deb75172da 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/ValueClassesUtils.kt @@ -88,7 +88,10 @@ fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean = contextReceivers.isEmpty() && receiverParameter == null && name == OperatorNameConventions.EQUALS && this@run.isInline && valueParameters.size == 1 - && (returnTypeRef.isBoolean || returnTypeRef.isNothing) - && valueParameters[0].returnTypeRef.coneType.let { it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection } + && returnTypeRef.coneType.fullyExpandedType(session).let { + it.isBoolean || it.isNothing + } && valueParameters[0].returnTypeRef.coneType.let { + it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection + } } - } ?: false + } == true diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt index 4f9d10265ad..ced09d2aea0 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/declarationUtils.kt @@ -17,7 +17,9 @@ import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneTypeSafe +import org.jetbrains.kotlin.fir.types.isNullableAny import org.jetbrains.kotlin.fir.types.toSymbol +import org.jetbrains.kotlin.util.OperatorNameConventions fun FirClass.constructors(session: FirSession): List { val result = mutableListOf() @@ -93,3 +95,12 @@ private fun FirFunction.containsDefaultValue(index: Int): Boolean = valueParamet fun FirFunction.itOrExpectHasDefaultParameterValue(index: Int): Boolean = containsDefaultValue(index) || symbol.getSingleExpectForActualOrNull()?.fir?.containsDefaultValue(index) == true + +fun FirSimpleFunction.isEquals(session: FirSession): Boolean { + if (name != OperatorNameConventions.EQUALS) return false + if (valueParameters.size != 1) return false + if (contextReceivers.isNotEmpty()) return false + if (receiverParameter != null) return false + val parameter = valueParameters.first() + return parameter.returnTypeRef.coneType.fullyExpandedType(session).isNullableAny +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassAnySynthesizedMemberScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassAnySynthesizedMemberScope.kt index 5433eacb97f..2efc77ec361 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassAnySynthesizedMemberScope.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirClassAnySynthesizedMemberScope.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl +import org.jetbrains.kotlin.fir.declarations.isEquals import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes @@ -46,7 +47,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled * This declared scope wrapper is created for data/value classes and provides Any method stubs, if necessary */ class FirClassAnySynthesizedMemberScope( - session: FirSession, + private val session: FirSession, private val declaredMemberScope: FirContainingNamesAwareScope, klass: FirRegularClass, scopeSession: ScopeSession, @@ -118,7 +119,7 @@ class FirClassAnySynthesizedMemberScope( } else -> { lazyResolveToPhase(FirResolvePhase.TYPES) - fir.isEquals() + fir.isEquals(session) } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 5bc9860d15e..66cdd4b25e6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -54,16 +54,17 @@ import kotlin.contracts.contract fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection): Boolean = isLambda && returnStatements.any { it is FirUnitExpression } -fun FirAnonymousFunction.addReturnToLastStatementIfNeeded() { +fun FirAnonymousFunction.addReturnToLastStatementIfNeeded(session: FirSession) { // If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement. // During conversion (to backend IR), the last expression will be coerced to Unit if needed. - if (returnTypeRef.isUnit) return + if (returnTypeRef.coneType.fullyExpandedType(session).isUnit) return val body = this.body ?: return val lastStatement = body.statements.lastOrNull() as? FirExpression ?: return if (lastStatement is FirReturnExpression) return val returnType = (body.typeRef as? FirResolvedTypeRef) ?: return + @OptIn(UnexpandedTypeCheck::class) if (returnType.isNothing) return val returnTarget = FirFunctionTarget(null, isLambda = isLambda).also { it.bind(this) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt index 836616025be..db4f612db4a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CallableReferenceResolution.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.createFunctionType import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedCallableReferenceTarget +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition import org.jetbrains.kotlin.fir.resolve.scope @@ -248,10 +249,14 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation( } } - val coercionStrategy = if (returnExpectedType.isUnitOrFlexibleUnit && !function.returnTypeRef.isUnit) - CoercionStrategy.COERCION_TO_UNIT - else - CoercionStrategy.NO_COERCION + val returnTypeRef = function.returnTypeRef + val coercionStrategy = + if (returnExpectedType.isUnitOrFlexibleUnit && + returnTypeRef.coneTypeSafe()?.fullyExpandedType(session)?.isUnit != true + ) + CoercionStrategy.COERCION_TO_UNIT + else + CoercionStrategy.NO_COERCION val adaptedArguments = if (expectedType.isBaseTypeForNumberedReferenceTypes) emptyMap() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index b5c8d828c28..b866654c6b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -536,7 +536,7 @@ abstract class FirDataFlowAnalyzer( return session.declaredMemberScope(this, memberRequiredPhase = FirResolvePhase.STATUS) .getFunctions(OperatorNameConventions.EQUALS) - .any { it.fir.isEquals() } + .any { it.fir.isEquals(session) } } // ----------------------------------- Jump ----------------------------------- @@ -1107,6 +1107,7 @@ abstract class FirDataFlowAnalyzer( } } + @OptIn(UnexpandedTypeCheck::class) fun exitElvis(elvisExpression: FirElvisExpression, isLhsNotNull: Boolean, callCompleted: Boolean) { val node = graphBuilder.exitElvis(isLhsNotNull, callCompleted) node.mergeIncomingFlow { flow -> diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 2f3e46dff7c..ffa11c87a0a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -1065,6 +1065,7 @@ class ControlFlowGraphBuilder { // it would be much easier if we could build calls after full completion only, at least for Nothing calls // KT-59726 // @returns `true` if node actually returned Nothing + @OptIn(UnexpandedTypeCheck::class) private fun completeFunctionCall(node: FunctionCallNode): Boolean { if (!node.fir.resultType.isNothing) return false val stub = StubNode(node.owner, node.level) @@ -1082,6 +1083,7 @@ class ControlFlowGraphBuilder { // ----------------------------------- Resolvable call ----------------------------------- + @OptIn(UnexpandedTypeCheck::class) fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression): QualifiedAccessNode { val returnsNothing = qualifiedAccessExpression.resultType.isNothing val node = createQualifiedAccessNode(qualifiedAccessExpression) @@ -1093,6 +1095,7 @@ class ControlFlowGraphBuilder { return node } + @OptIn(UnexpandedTypeCheck::class) fun exitSmartCastExpression(smartCastExpression: FirSmartCastExpression): SmartCastExpressionExitNode { val returnsNothing = smartCastExpression.resultType.isNothing val node = createSmartCastExitNode(smartCastExpression) @@ -1126,6 +1129,7 @@ class ControlFlowGraphBuilder { return argumentListSplitNodes.pop()?.also { addNewSimpleNode(it) } } + @OptIn(UnexpandedTypeCheck::class) fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode { val returnsNothing = functionCall.resultType.isNothing val node = createFunctionCallNode(functionCall) @@ -1171,6 +1175,7 @@ class ControlFlowGraphBuilder { return createThrowExceptionNode(throwExpression).also { addNonSuccessfullyTerminatingNode(it) } } + @OptIn(UnexpandedTypeCheck::class) fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode { val node = createCheckNotNullCallNode(checkNotNullCall) unifyDataFlowFromPostponedLambdas(node, callCompleted) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 8dd1668aaf5..075e3eb6959 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -249,7 +249,7 @@ class FirCallCompletionResultsWriterTransformer( } if (enableArrayOfCallTransformation) { - return arrayOfCallTransformer.transformFunctionCall(result, null) + return arrayOfCallTransformer.transformFunctionCall(result, session) } return result @@ -618,7 +618,7 @@ class FirCallCompletionResultsWriterTransformer( session.lookupTracker?.recordTypeResolveAsLookup(result.typeRef, result.source, context.file.source) } // Have to delay this until the type is written to avoid adding a return if the type is Unit. - result.addReturnToLastStatementIfNeeded() + result.addReturnToLastStatementIfNeeded(session) return result } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt index 0a3761d9838..1c78aefd95a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirWhenExhaustivenessTransformer.kt @@ -214,6 +214,7 @@ private object WhenOnNullableExhaustivenessChecker : WhenExhaustivenessChecker() private object ConditionChecker : AbstractConditionChecker() { override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Flags) { val argument = equalityOperatorCall.arguments[1] + @OptIn(UnexpandedTypeCheck::class) if (argument.typeRef.isNullableNothing) { data.containsNull = true } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt index 2555cf54b9c..5548b4e988d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirArrayOfCallTransformer.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.expressions.* @@ -14,7 +15,10 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.fir.types.isArrayType import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer @@ -23,9 +27,9 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer * * Note that arrayOf() calls only in [FirAnnotation] or the default value of annotation constructor are transformed. */ -class FirArrayOfCallTransformer : FirDefaultTransformer() { - private fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? { - if (!functionCall.isArrayOfCall) return null +class FirArrayOfCallTransformer : FirDefaultTransformer() { + private fun toArrayOfCall(functionCall: FirFunctionCall, session: FirSession): FirArrayOfCall? { + if (!functionCall.isArrayOfCall(session)) return null if (functionCall.calleeReference !is FirResolvedNamedReference) return null return buildArrayOfCall { source = functionCall.source @@ -42,25 +46,25 @@ class FirArrayOfCallTransformer : FirDefaultTransformer() { } } - override fun transformFunctionCall(functionCall: FirFunctionCall, data: Nothing?): FirStatement { + override fun transformFunctionCall(functionCall: FirFunctionCall, data: FirSession): FirStatement { functionCall.transformChildren(this, data) - return toArrayOfCall(functionCall) ?: functionCall + return toArrayOfCall(functionCall, data) ?: functionCall } - override fun transformElement(element: E, data: Nothing?): E { + override fun transformElement(element: E, data: FirSession): E { @Suppress("UNCHECKED_CAST") return (element.transformChildren(this, data) as E) } companion object { - val FirFunctionCall.isArrayOfCall: Boolean - get() { - val function: FirCallableDeclaration = getOriginalFunction() ?: return false - return function is FirSimpleFunction && - function.returnTypeRef.isArrayType && - isArrayOf(function, arguments) && - function.receiverParameter == null - } + fun FirFunctionCall.isArrayOfCall(session: FirSession): Boolean { + val function: FirCallableDeclaration = getOriginalFunction() ?: return false + val returnTypeRef = function.returnTypeRef + return function is FirSimpleFunction && + returnTypeRef.coneTypeSafe()?.fullyExpandedType(session)?.isArrayType == true && + isArrayOf(function, arguments) && + function.receiverParameter == null + } private val arrayOfNames = hashSetOf("kotlin/arrayOf") + hashSetOf( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 54bae84a512..b23fb7b6976 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -860,7 +860,7 @@ open class FirDeclarationsResolveTransformer( lambda.replaceTypeRef(lambda.constructFunctionTypeRef(session, resolvedLambdaAtom?.expectedFunctionTypeKind)) session.lookupTracker?.recordTypeResolveAsLookup(lambda.typeRef, lambda.source, context.file.source) - lambda.addReturnToLastStatementIfNeeded() + lambda.addReturnToLastStatementIfNeeded(session) return lambda } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 5408c8bbcac..996e01b7e97 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -451,7 +451,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT addReceiversFromExtensions(result) if (enableArrayOfCallTransformation) { - return arrayOfCallTransformer.transformFunctionCall(result, null) + return arrayOfCallTransformer.transformFunctionCall(result, session) } return result } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index f1f52d08bcb..10ac5189b4f 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.impl.FirImplicitNothingTypeRef import org.jetbrains.kotlin.fir.types.isNothing @@ -815,6 +816,8 @@ object FirStub : FirExpression() { override fun transformAnnotations(transformer: FirTransformer, data: D): FirExpression = this override fun transformChildren(transformer: FirTransformer, data: D): FirElement = this override fun replaceAnnotations(newAnnotations: List) { assert(newAnnotations.isEmpty()) } + + @OptIn(UnexpandedTypeCheck::class) override fun replaceTypeRef(newTypeRef: FirTypeRef) { assert(newTypeRef.isNothing) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt index 6d590ace061..cf757b7734d 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt @@ -96,12 +96,3 @@ val FirCallableSymbol<*>.isExtension: Boolean is FirProperty -> fir.receiverParameter != null is FirVariable -> false } - -fun FirSimpleFunction.isEquals(): Boolean { - if (name != OperatorNameConventions.EQUALS) return false - if (valueParameters.size != 1) return false - if (contextReceivers.isNotEmpty()) return false - if (receiverParameter != null) return false - val parameter = valueParameters.first() - return parameter.returnTypeRef.isNullableAny -} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt index 3971f27c155..98c0f0ec78b 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt @@ -34,15 +34,40 @@ val FirTypeRef.coneType: ConeKotlinType val FirTypeRef.coneTypeOrNull: ConeKotlinType? get() = coneTypeSafe() +@RequiresOptIn( + "This type check never expands type aliases. Use with care (probably Ok for expression & constructor types). " + + "Generally this.coneType.fullyExpandedType(session).isSomeType is better" +) +annotation class UnexpandedTypeCheck + +@UnexpandedTypeCheck val FirTypeRef.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, false) + +@UnexpandedTypeCheck val FirTypeRef.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true) + +@UnexpandedTypeCheck val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false) + +@UnexpandedTypeCheck val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true) + +@UnexpandedTypeCheck val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false) + +@UnexpandedTypeCheck val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false) + +@UnexpandedTypeCheck val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false) + +@UnexpandedTypeCheck val FirTypeRef.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false) + +@UnexpandedTypeCheck val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false) + +@UnexpandedTypeCheck val FirTypeRef.isArrayType: Boolean get() = isBuiltinType(StandardClassIds.Array, false)