diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index abd9ae834d4..f1e582641c7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -470,9 +470,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { List catchClauses = expression.getCatchClauses(); KtFinallySection finallyBlock = expression.getFinallyBlock(); List types = new ArrayList(); + boolean nothingInAllCatchBranches = true; for (KtCatchClause catchClause : catchClauses) { KtParameter catchParameter = catchClause.getCatchParameter(); KtExpression catchBody = catchClause.getCatchBody(); + boolean nothingInCatchBranch = false; if (catchParameter != null) { components.identifierChecker.checkDeclaration(catchParameter, context.trace); ModifiersChecker.ModifiersCheckingProcedure modifiersChecking = components.modifiersChecker.withTrace(context.trace); @@ -494,18 +496,28 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { KotlinType type = facade.getTypeInfo(catchBody, context.replaceScope(catchScope)).getType(); if (type != null) { types.add(type); + if (KotlinBuiltIns.isNothing(type)) { + nothingInCatchBranch = true; + } } } } + if (!nothingInCatchBranch) { + nothingInAllCatchBranches = false; + } } KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context); + KotlinTypeInfo tryResult = facade.getTypeInfo(tryBlock, context); if (finallyBlock != null) { result = facade.getTypeInfo(finallyBlock.getFinalExpression(), context.replaceExpectedType(NO_EXPECTED_TYPE)); } + else if (nothingInAllCatchBranches) { + result = tryResult; + } - KotlinType type = facade.getTypeInfo(tryBlock, context).getType(); + KotlinType type = tryResult.getType(); if (type != null) { types.add(type); } diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.kt new file mode 100644 index 00000000000..8ef22d30b74 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.kt @@ -0,0 +1,80 @@ +// See also KT-10735 +fun test() { + var a: Int? + try { + a = 3 + } + catch (e: Exception) { + return + } + a.hashCode() // a is never null here +} +class A: Exception() +class B: Exception() +fun test2() { + var a: Int? + try { + a = 4 + } + catch (e: A) { + return + } + catch (e: B) { + return + } + a.hashCode() // a is never null here +} +fun test3() { + var a: Int? = null + try { + a = 5 + } + catch (e: A) { + // do nothing + } + catch (e: B) { + return + } + a.hashCode() // a is nullable here +} +fun test4() { + var a: Int? = null + try { + // do nothing + } + catch (e: A) { + return + } + catch (e: B) { + return + } + a.hashCode() // a is nullable here +} +fun test5() { + var a: Int?// = null + try { + a = 3 + } + catch (e: Exception) { + return + } + finally { + // Error: KT-9825 + a = 5 + } + a.hashCode() // a is never null here +} +fun test6() { + var a: Int?// = null + try { + a = 3 + } + catch (e: Exception) { + return + } + finally { + // Error: KT-9825 + a = null + } + a.hashCode() // a is null here +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.txt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.txt new file mode 100644 index 00000000000..917a26e2ab0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.txt @@ -0,0 +1,26 @@ +package + +public fun test(): kotlin.Unit +public fun test2(): kotlin.Unit +public fun test3(): kotlin.Unit +public fun test4(): kotlin.Unit +public fun test5(): kotlin.Unit +public fun test6(): kotlin.Unit + +public final class A : java.lang.Exception { + public constructor A() + public final override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public final override /*1*/ /*fake_override*/ val message: kotlin.String? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B : java.lang.Exception { + public constructor B() + public final override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public final override /*1*/ /*fake_override*/ val message: kotlin.String? + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 03f4139b9e1..f3a1405035b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -17066,6 +17066,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("initInTryReturnInCatch.kt") + public void testInitInTryReturnInCatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/varnotnull/initInTryReturnInCatch.kt"); + doTest(fileName); + } + @TestMetadata("initialization.kt") public void testInitialization() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/varnotnull/initialization.kt");