diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt index 1e253b1f2dd..5041043b1c8 100644 --- a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt @@ -1,5 +1,6 @@ FILE: catchParameter.kt - public final fun test(): R|kotlin/Unit| { + public final typealias StringType = R|kotlin/String| + public final fun test(): R|kotlin/Unit| { try { } catch (e: R|kotlin/NullPointerException| = R|java/lang/NullPointerException.NullPointerException|()) { @@ -10,6 +11,26 @@ FILE: catchParameter.kt catch (e: R|T|) { } + try { + } + catch (e: R|() -> kotlin/Int|) { + } + + try { + } + catch (e: R|StringType|) { + } + + try { + } + catch (e: R|kotlin/Int| = Int(5)) { + } + + try { + } + catch (e: R|kotlin/Throwable|) { + } + } public final inline fun anotherTest(): R|kotlin/Unit| { try { @@ -17,4 +38,4 @@ FILE: catchParameter.kt catch (e: R|T|) { } - } \ No newline at end of file + } diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt index 0a0f2b86410..e1a5d34d99e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt @@ -1,4 +1,6 @@ -fun test() { +typealias StringType = String + +fun test() { try { } catch (e: NullPointerException = NullPointerException()) { @@ -6,8 +8,16 @@ fun test() { } try {} catch (e: T) {} + + try {} catch (e: () -> Int) {} + + try {} catch (e: StringType) {} + + try {} catch (e: Int = 5) {} + + try {} catch (e: Throwable) {} } inline fun anotherTest() { - try {} catch (e: T) {} -} \ No newline at end of file + try {} catch (e: T) {} +} 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 2b5a7f6f0d4..d6920b5813a 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 @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSymbolOwner +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier @@ -22,18 +23,18 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.firSymbolProvider +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope +import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtModifierList diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt index 4205522572c..5a58000782c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -5,31 +5,50 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.expressions.FirTryExpression +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeParameterType import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.constructClassLikeType object FirCatchParameterChecker : FirTryExpressionChecker() { + private val throwable = StandardClassIds.byName("Throwable") + .constructClassLikeType(emptyArray(), false) + override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { for (catchEntry in expression.catches) { val catchParameter = catchEntry.parameter if (catchParameter.defaultValue != null) - reporter.report(catchParameter.source?.let { FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it)) } val typeRef = catchParameter.returnTypeRef - if (typeRef is FirResolvedTypeRef && typeRef.type is ConeTypeParameterType) { - val isReified = (typeRef.type as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir.isReified + if (typeRef !is FirResolvedTypeRef) return + + val coneType = typeRef.type + if (coneType is ConeTypeParameterType) { + val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified if (isReified) { - reporter.report(catchParameter.source?.let { FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it)) } } else { - reporter.report(catchParameter.source?.let { FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it)) } } } + + if (!coneType.isThrowable(context.session)) + catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwable, coneType)) } } } + + private fun ConeKotlinType.isThrowable(session: FirSession) = + throwable.isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt index 9da253daa3b..5d076cdc2e1 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt @@ -109,7 +109,7 @@ fun t7() : Int { return 1 2 } - catch (e : Any) { + catch (e : Any) { 2 } return 1 // this is OK, like in Java @@ -120,7 +120,7 @@ fun t8() : Int { return 1 2 } - catch (e : Any) { + catch (e : Any) { return 1 2 }