diff --git a/compiler/fir/checkers/checkers.js/build.gradle.kts b/compiler/fir/checkers/checkers.js/build.gradle.kts index afed60b76a3..e2ce96adbe3 100644 --- a/compiler/fir/checkers/checkers.js/build.gradle.kts +++ b/compiler/fir/checkers/checkers.js/build.gradle.kts @@ -11,7 +11,7 @@ dependencies { api(project(":compiler:fir:checkers")) // FE checks for modules use ModuleKind - // This dependency can be removed when we stop supporting PLANE and UMD module systems + // This dependency can be removed when we stop supporting PLAIN and UMD module systems implementation(project(":js:js.serializer")) /* diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt index 22c18d1ab14..98dbcce0204 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsHelpers.kt @@ -157,10 +157,7 @@ internal fun FirClass.superClassNotAny(session: FirSession) = superConeTypes .filterNot { it.isAny || it.isNullableAny } .find { it.toSymbol(session)?.classKind == ClassKind.CLASS } -internal fun getRootDeclarationSymbol(symbol: FirBasedSymbol<*>, session: FirSession): FirBasedSymbol<*> { - return generateSequence(symbol) { it.getContainingClassSymbol(session) }.last() +internal fun getRootClassLikeSymbolOrSelf(symbol: FirBasedSymbol<*>, session: FirSession): FirBasedSymbol<*> { + return symbol.getContainingClassSymbol(session)?.let { getRootClassLikeSymbolOrSelf(it, session) } ?: symbol } -internal fun isTopLevelSymbol(symbol: FirBasedSymbol<*>, session: FirSession): Boolean { - return symbol.getContainingClassSymbol(session) == null -} diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsModuleCheckUtils.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsModuleCheckUtils.kt index 859b0bd32a3..61ead153383 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsModuleCheckUtils.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/FirJsModuleCheckUtils.kt @@ -37,7 +37,7 @@ internal fun checkJsModuleUsage( val moduleKind = context.session.jsModuleKind val calleeSession = callee.moduleData.session - val calleeRoot = getRootDeclarationSymbol(callee, calleeSession) + val calleeRoot = getRootClassLikeSymbolOrSelf(callee, calleeSession) val calleeContainingFile = calleeRoot.getContainingFile(calleeSession) val callToModule = calleeRoot.getAnnotationStringParameter(JsStandardClassIds.Annotations.JsModule, calleeSession) != null || diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsModuleQualifiedAccessChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsModuleQualifiedAccessChecker.kt index 27952fa23b5..05456466e1c 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsModuleQualifiedAccessChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsModuleQualifiedAccessChecker.kt @@ -9,15 +9,12 @@ import org.jetbrains.kotlin.AbstractKtSourceElement import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessExpressionChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol import org.jetbrains.kotlin.fir.analysis.js.checkers.checkJsModuleUsage -import org.jetbrains.kotlin.fir.analysis.js.checkers.isTopLevelSymbol import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression import org.jetbrains.kotlin.fir.references.toResolvedBaseSymbol -import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol -import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance -import org.jetbrains.kotlin.fir.types.coneTypeOrNull import org.jetbrains.kotlin.fir.types.toRegularClassSymbol object FirJsModuleQualifiedAccessChecker : FirQualifiedAccessExpressionChecker() { @@ -34,7 +31,7 @@ object FirJsModuleQualifiedAccessChecker : FirQualifiedAccessExpressionChecker() expression: FirQualifiedAccessExpression ): List, AbstractKtSourceElement?>> { val calleeSymbol = expression.calleeReference.toResolvedBaseSymbol() - if (calleeSymbol != null && isTopLevelSymbol(calleeSymbol, calleeSymbol.moduleData.session)) { + if (calleeSymbol != null && calleeSymbol.getContainingClassSymbol(calleeSymbol.moduleData.session) == null) { return listOf(calleeSymbol to expression.calleeReference.source) } @@ -53,14 +50,10 @@ object FirJsModuleQualifiedAccessChecker : FirQualifiedAccessExpressionChecker() } private fun checkReifiedTypeParameters(expr: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { - val functionSymbol = (expr as? FirFunctionCall)?.calleeReference?.toResolvedFunctionSymbol() ?: return - for ((typeParameterSymbol, typeArgument) in functionSymbol.typeParameterSymbols.zip(expr.typeArguments)) { - if (typeParameterSymbol.isReified) { - val type = (typeArgument as? FirTypeProjectionWithVariance)?.typeRef?.coneTypeOrNull ?: continue - val typeArgumentClass = type.toRegularClassSymbol(context.session) ?: continue - val source = typeArgument.source ?: expr.calleeReference.source ?: expr.source - checkJsModuleUsage(typeArgumentClass, context, reporter, source) - } + (expr as? FirFunctionCall)?.forAllReifiedTypeParameters { type, typeArgument -> + val typeArgumentClass = type.toRegularClassSymbol(context.session) ?: return@forAllReifiedTypeParameters + val source = typeArgument.source ?: expr.calleeReference.source ?: expr.source + checkJsModuleUsage(typeArgumentClass, context, reporter, source) } } } diff --git a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsReifiedExternalChecker.kt b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsReifiedExternalChecker.kt index 5418b4e6c4b..1ac3d12094e 100644 --- a/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsReifiedExternalChecker.kt +++ b/compiler/fir/checkers/checkers.js/src/org/jetbrains/kotlin/fir/analysis/js/checkers/expression/FirJsReifiedExternalChecker.kt @@ -12,28 +12,21 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChec import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors import org.jetbrains.kotlin.fir.analysis.js.checkers.isNativeInterface import org.jetbrains.kotlin.fir.expressions.FirFunctionCall -import org.jetbrains.kotlin.fir.references.toResolvedFunctionSymbol -import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance -import org.jetbrains.kotlin.fir.types.coneTypeOrNull +import org.jetbrains.kotlin.fir.expressions.forAllReifiedTypeParameters import org.jetbrains.kotlin.fir.types.toSymbol object FirJsReifiedExternalChecker : FirFunctionCallChecker() { override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) { - val functionSymbol = expression.calleeReference.toResolvedFunctionSymbol() ?: return - for ((typeParameterSymbol, typeArgument) in functionSymbol.typeParameterSymbols.zip(expression.typeArguments)) { - if (typeParameterSymbol.isReified) { - val type = (typeArgument as? FirTypeProjectionWithVariance)?.typeRef?.coneTypeOrNull ?: continue - val typeSymbol = type.toSymbol(context.session) ?: continue - if (typeSymbol.isNativeInterface(context)) { - reporter.reportOn( - typeArgument.source ?: expression.source, - FirJsErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT, - type, - context - ) - } + expression.forAllReifiedTypeParameters { type, typeArgument -> + val typeSymbol = type.toSymbol(context.session) + if (typeSymbol?.isNativeInterface(context) == true) { + reporter.reportOn( + typeArgument.source ?: expression.source, + FirJsErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT, + type, + context + ) } } } - } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt index 61d8e7908b3..1ca99503dab 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCastOperatorsChecker.kt @@ -28,35 +28,28 @@ object FirCastOperatorsChecker : FirTypeOperatorCallChecker() { val conversionTypeRef = expression.conversionTypeRef val targetType = conversionTypeRef.coneType.fullyExpandedType(session) + if (expression.operation in FirOperation.TYPES && targetType is ConeDynamicType) { + reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context) + } + val isSafeAs = expression.operation == FirOperation.SAFE_AS if (expression.operation == FirOperation.AS || isSafeAs) { - if (targetType is ConeDynamicType) { - reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context) - } else { - val castType = checkCasting(actualType, targetType, isSafeAs, context) - if (castType == CastingType.Impossible) { - if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) { - reporter.reportOn(expression.source, FirErrors.CAST_NEVER_SUCCEEDS, context) - } - } else if (castType == CastingType.Always) { - if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) { - reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context) - } - } else if (isCastErased(actualType, targetType, context)) { - reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context) + val castType = checkCasting(actualType, targetType, isSafeAs, context) + if (castType == CastingType.Impossible) { + if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) { + reporter.reportOn(expression.source, FirErrors.CAST_NEVER_SUCCEEDS, context) } + } else if (castType == CastingType.Always) { + if (context.languageVersionSettings.supportsFeature(LanguageFeature.EnableDfaWarningsInK2)) { + reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context) + } + } else if (isCastErased(actualType, targetType, context)) { + reporter.reportOn(expression.source, FirErrors.UNCHECKED_CAST, actualType, targetType, context) } } else if (expression.operation == FirOperation.IS) { - if (targetType is ConeDynamicType) { - reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context) - } if (!context.isContractBody && isCastErased(actualType, targetType, context)) { reporter.reportOn(conversionTypeRef.source, FirErrors.CANNOT_CHECK_FOR_ERASED, targetType, context) } - } else if (expression.operation == FirOperation.NOT_IS) { - if (targetType is ConeDynamicType) { - reporter.reportOn(conversionTypeRef.source, FirErrors.DYNAMIC_NOT_ALLOWED, context) - } } } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt index e8dbdd04d29..352a4f60ffa 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirExpressionUtil.kt @@ -20,8 +20,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.TransformData @@ -177,3 +176,14 @@ val FirQualifiedAccessExpression.allReceiverExpressions: List addIfNotNull(extensionReceiver) addAll(contextReceiverArguments) } + +inline fun FirFunctionCall.forAllReifiedTypeParameters(block: (ConeKotlinType, FirTypeProjectionWithVariance) -> Unit) { + val functionSymbol = calleeReference.toResolvedFunctionSymbol() ?: return + + for ((typeParameterSymbol, typeArgument) in functionSymbol.typeParameterSymbols.zip(typeArguments)) { + if (typeParameterSymbol.isReified && typeArgument is FirTypeProjectionWithVariance) { + val type = typeArgument.typeRef.coneTypeOrNull ?: continue + block(type, typeArgument) + } + } +}