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 0d8c4fae9d9..5c5a42158ba 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -555,6 +555,30 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { DataFlowInfo dataFlowInfoBeforeTry = tryInputContext.dataFlowInfo; + /* tryOutputContext is tryInputContext rom which all dataFlowInfo about vars + * assigned inside try block has been cut. E.g.: + * var s: String? = ... + * var x: String? = null + * x = "" // here we have DFI that x != null and it is tryInputContext + * try { + * x = null // here was assignment so we cut info about x from context + * // or + * x = "42" + * requireNotNull(s) + * } // here we have tryOutputContext with no info about x + * // Notice, that in tryOutputContext we also have no info about s + * // tryOutputContext is just cut tryInputContext + * catch (...) { } + * ... + * + */ + + PreliminaryLoopVisitor tryVisitor = PreliminaryLoopVisitor.visitTryBlock(tryExpression); + ExpressionTypingContext tryOutputContext = tryInputContext.replaceDataFlowInfo( + tryVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoBeforeTry, components.languageVersionSettings) + ); + DataFlowInfo dataFlowInfoAfterTry = tryOutputContext.dataFlowInfo; + List catchBlocks = Lists.newArrayList(); List> catchClausesBlocksAndParameters = Lists.newArrayList(); @@ -580,14 +604,23 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { Call callForTry = createCallForSpecialConstruction(tryExpression, tryExpression, arguments); - MutableDataFlowInfoForArguments dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoBeforeTry); + MutableDataFlowInfoForArguments dataFlowInfoForArguments; + if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewDataFlowForTryExpressions)) { + dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoAfterTry); + } else { + dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfTryCall(callForTry, dataFlowInfoBeforeTry, dataFlowInfoBeforeTry); + } ResolvedCall resolvedCall = components.controlStructureTypingUtils .resolveTryAsCall(callForTry, tryExpression, catchClausesBlocksAndParameters, tryInputContext, dataFlowInfoForArguments); KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType(); BindingContext bindingContext = tryInputContext.trace.getBindingContext(); - return processTryBranches(tryExpression, tryBlock, tryInputContext, catchBlocks, finallyBlock, bindingContext, resultType); + if (components.languageVersionSettings.supportsFeature(LanguageFeature.NewDataFlowForTryExpressions)) { + return processTryBranchesWithNewDataFlowAlgorithm(tryExpression, tryBlock, tryOutputContext, dataFlowInfoAfterTry, catchBlocks, finallyBlock, bindingContext, resultType); + } else { + return processTryBranches(tryExpression, tryBlock, tryInputContext, catchBlocks, finallyBlock, bindingContext, resultType); + } } @NotNull @@ -611,6 +644,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { boolean nothingInAllCatchBranches = isCatchBranchesReturnsNothing(catchBlocks, bindingContext); // it is not actually correct way (#KT-28370) of computing context, but it's how was in OI + // Fix of it is breaking change and allowed with NewDataFlowForTryExpressions language feature. + // See [processTryBranchesWithNewDataFlowAlgorithm] function ExpressionTypingContext tryOutputContext = getCleanedContextFromTryWithAssignmentsToVar(tryExpression, nothingInAllCatchBranches, context); KotlinTypeInfo result = TypeInfoFactoryKt.createTypeInfo(resultType, tryOutputContext); @@ -627,6 +662,75 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } } + @NotNull + private KotlinTypeInfo processTryBranchesWithNewDataFlowAlgorithm( + @NotNull KtTryExpression tryExpression, + KtBlockExpression tryBlock, + ExpressionTypingContext tryOutputContext, + DataFlowInfo dataFlowInfoAfterTry, + List catchBlocks, + KtBlockExpression finallyBlock, + BindingContext bindingContext, + KotlinType resultType + ) { + /* + * See [resolveTryExpressionWithNewInference] for the definition of tryOutputContext + * Here was added some others context and another definitions: + * - catchOutputContextFromNonNothingBranches is a tryOutputContext without information about variables + * assigned in non-Nothing catch branches + * - catchOutputContextFromAllBranches is tryOutputContext that was cut with assignments from all catch branches + * - tryInfo is resolved KotlinTypeInfo of try branch, so its dataFlowInfo contains all interesting infos from try block + * (e.g. info about s != null from example in function [resolveTryExpressionWithNewInference]) + * - finallyTypeInfo is resolved KotlinTypeInfo of finally branch (it's resolved with assumption that we can came into + * finally block from any catch block, even if it returns Nothing) + * - resultDataFlowInfo is dataFlowInfo that leaves after try/catch/finally (if catch or finally is presented) + * + * + * All analysis passes under strict assumption, that we can fail with exception in any place of try block, so we can't use any + * resolved dataFlowInfo from it. But, there is a one case, when we can use it: if there are no catch branches or all catch + * branches returns Nothing, so we can reach code after try only if there was no exceptions in try block, so we can use + * dataFlowInfo from it (see nothingInAllCatchBranches variable) + */ + List branchesReturningNothing = whichCatchBranchesReturnNothing(catchBlocks, bindingContext); + PreliminaryLoopVisitor catchVisitorForNonNothingBranches = PreliminaryLoopVisitor.visitCatchBlocks(tryExpression, mapNot(branchesReturningNothing)); + ExpressionTypingContext catchOutputContextFromNonNothingBranches = tryOutputContext.replaceDataFlowInfo( + catchVisitorForNonNothingBranches.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoAfterTry, components.languageVersionSettings) + ); + + KotlinTypeInfo tryInfo = BindingContextUtils.getRecordedTypeInfo(tryBlock, bindingContext); + boolean nothingInAllCatchBranches = CollectionsKt.all(branchesReturningNothing, it -> it); + DataFlowInfo nonExceptionalTryCatchesOutputInfo; + if (tryInfo == null) { + nonExceptionalTryCatchesOutputInfo = DataFlowInfo.Companion.getEMPTY(); + } else if (nothingInAllCatchBranches) { + nonExceptionalTryCatchesOutputInfo = tryInfo.getDataFlowInfo(); + } else { + nonExceptionalTryCatchesOutputInfo = catchOutputContextFromNonNothingBranches.dataFlowInfo; + } + + DataFlowInfo resultDataFlowInfo; + if (finallyBlock != null) { + PreliminaryLoopVisitor catchVisitor = PreliminaryLoopVisitor.visitCatchBlocks(tryExpression); + ExpressionTypingContext catchOutputContextFromAllBranches = tryOutputContext.replaceDataFlowInfo( + catchVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfoAfterTry, components.languageVersionSettings) + ); + KotlinTypeInfo finallyTypeInfo = facade.getTypeInfo(finallyBlock, catchOutputContextFromAllBranches); + DataFlowInfo finallyDataFlowInfo = finallyTypeInfo.getDataFlowInfo(); + resultDataFlowInfo = finallyDataFlowInfo.and(nonExceptionalTryCatchesOutputInfo); + } else { + resultDataFlowInfo = nonExceptionalTryCatchesOutputInfo; + } + + return TypeInfoFactoryKt.createTypeInfo( + components.dataFlowAnalyzer.checkType(resultType, tryExpression, catchOutputContextFromNonNothingBranches), + resultDataFlowInfo + ); + } + + private static List mapNot(List list) { + return CollectionsKt.map(list, it -> !it); + } + private static boolean isCatchBranchesReturnsNothing(List catchBlocks, BindingContext bindingContext) { return CollectionsKt.all(whichCatchBranchesReturnNothing(catchBlocks, bindingContext), it -> it); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt index 6e788c0408c..0e3fce910de 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt @@ -73,5 +73,20 @@ class PreliminaryLoopVisitor private constructor() : AssignedVariablesSearcher() tryExpression.tryBlock.accept(visitor, null) return visitor } + + @JvmStatic + fun visitCatchBlocks(tryExpression: KtTryExpression): PreliminaryLoopVisitor = + visitCatchBlocks(tryExpression, tryExpression.catchClauses.map { true }) + + @JvmStatic + fun visitCatchBlocks(tryExpression: KtTryExpression, isBlockShouldBeVisited: List): PreliminaryLoopVisitor { + val catchClauses = tryExpression.catchClauses + assert(catchClauses.size == isBlockShouldBeVisited.size) + val visitor = PreliminaryLoopVisitor() + catchClauses.zip(isBlockShouldBeVisited) + .filter { (_, shouldBeVisited) -> shouldBeVisited } + .forEach { (clause, _) -> clause.catchBody?.accept(visitor, null) } + return visitor + } } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt new file mode 100644 index 00000000000..0512099a67e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt @@ -0,0 +1,88 @@ +// !WITH_NEW_INFERENCE +// !LANGUAGE: +NewDataFlowForTryExpressions +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER +// Related issue: KT-28370 + +class ExcA : Exception() +class ExcB : Exception() + +fun test1(s: String?) { + var t2: Boolean? = true + if (t2 != null) { + try { + t2 = null + } + catch (e: Exception) { + requireNotNull(s) + } + t2.not() + s.length + } +} + +fun test2(s: String?) { + var t2: Boolean? = true + if (t2 != null) { + try { + t2 = null + } + finally { + requireNotNull(s) + t2 = true + } + t2.not() + s.length + } +} + +fun test3() { + var s: String? = null + s = "" + try { + + } + catch (e: Exception) { + s = null + return + } + s.length +} + +fun test4() { + var s: String? = null + s = "" + try { + + } + catch (e: ExcA) { + s = null + return + } + catch (e: ExcB) { + + } + s.length +} + +fun test5(s: String?) { + try { + requireNotNull(s) + } + catch (e: ExcA) { + return + } + catch (e: ExcB) { + + } + s.length +} + +fun test6(s: String?) { + try { + requireNotNull(s) + } + catch (e: Exception) { + return + } + s.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.txt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.txt new file mode 100644 index 00000000000..52026a884f5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.txt @@ -0,0 +1,46 @@ +package + +public fun test1(/*0*/ s: kotlin.String?): kotlin.Unit +public fun test2(/*0*/ s: kotlin.String?): kotlin.Unit +public fun test3(): kotlin.Unit +public fun test4(): kotlin.Unit +public fun test5(/*0*/ s: kotlin.String?): kotlin.Unit +public fun test6(/*0*/ s: kotlin.String?): kotlin.Unit + +public final class ExcA : kotlin.Exception /* = java.lang.Exception */ { + public constructor ExcA() + public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public open override /*1*/ /*fake_override*/ val message: kotlin.String? + public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>! + public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ExcB : kotlin.Exception /* = java.lang.Exception */ { + public constructor ExcB() + public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public open override /*1*/ /*fake_override*/ val message: kotlin.String? + public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>! + public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt new file mode 100644 index 00000000000..f516d803a08 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt @@ -0,0 +1,20 @@ +// !WITH_NEW_INFERENCE +// !LANGUAGE: +NewDataFlowForTryExpressions +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER +// Related issue: KT-28370 + +fun test1(s1: String?) { + var s: String? = null + s = "" + try { + s = "" + requireNotNull(s1) + } + catch (e: Exception) { + return + } + finally { + s.length + } + s.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.txt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.txt new file mode 100644 index 00000000000..f1c7443a56e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.txt @@ -0,0 +1,3 @@ +package + +public fun test1(/*0*/ s1: kotlin.String?): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt new file mode 100644 index 00000000000..f8159f6070e --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt @@ -0,0 +1,107 @@ +// !WITH_NEW_INFERENCE +// !LANGUAGE: +NewDataFlowForTryExpressions +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_VALUE -VARIABLE_WITH_REDUNDANT_INITIALIZER +// Related issue: KT-28370 + +class ExcA : Exception() +class ExcB : Exception() + +fun test1() { + var x: String? = null + x = "" + + try { + x = null + } catch (e: Exception) { + x.length // smartcast shouldn't be allowed (OOME could happen after `x = null`) + throw e + } + finally { + // smartcast shouldn't be allowed, `x = null` could've happened + x.length + } + // smartcast shouldn't be allowed, `x = null` could've happened + x.length +} + +// With old DFA of try/catch info about unsound smartcasts after try +// removes only if there is at least one catch branch that not returns Nothing +fun test2() { + var x: String? = null + x = "" + + try { + x = null + } catch (e: Exception) { + // BAD + x.length + } + finally { + x.length + } + x.length +} + +fun test3() { + var t2: Boolean? = true + if (t2 != null) { // or `t2 is Boolean` + try { + throw Exception() + } catch (e: Exception) { + t2 = null + } + t2.not() // wrong smartcast, NPE + } +} + +fun test4() { + var t2: Boolean? = true + if (t2 != null) { // or `t2 is Boolean` + try { + t2 = null + } finally { } + t2.not() // wrong smartcast, NPE + } +} + +fun test5() { + var s1: String? = null + var s2: String? = null + s1 = "" + s2 = "" + try { + TODO() + } + catch (e: ExcA) { + s1 = "" + } + catch (e: ExcB) { + s2 = null + return + } + finally { + s1.length + s2.length + } + s1.length + s2.length +} + +fun test6(s1: String?, s2: String?) { + var s: String? = null + s = "" + try { + s = null + requireNotNull(s1) + } + catch (e: Exception) { + return + } + finally { + s.length + requireNotNull(s2) + } + s.length + s1.length + s2.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.txt b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.txt new file mode 100644 index 00000000000..eee9a3ef422 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.txt @@ -0,0 +1,46 @@ +package + +public fun test1(): 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(/*0*/ s1: kotlin.String?, /*1*/ s2: kotlin.String?): kotlin.Unit + +public final class ExcA : kotlin.Exception /* = java.lang.Exception */ { + public constructor ExcA() + public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public open override /*1*/ /*fake_override*/ val message: kotlin.String? + public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>! + public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class ExcB : kotlin.Exception /* = java.lang.Exception */ { + public constructor ExcB() + public open override /*1*/ /*fake_override*/ val cause: kotlin.Throwable? + public open override /*1*/ /*fake_override*/ val message: kotlin.String? + public final override /*1*/ /*fake_override*/ fun addSuppressed(/*0*/ exception: kotlin.Throwable!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun fillInStackTrace(): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun getLocalizedMessage(): kotlin.String! + public open override /*1*/ /*fake_override*/ fun getStackTrace(): kotlin.Array<(out) java.lang.StackTraceElement!>! + public final override /*1*/ /*fake_override*/ fun getSuppressed(): kotlin.Array<(out) kotlin.Throwable!>! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun initCause(/*0*/ cause: kotlin.Throwable!): kotlin.Throwable! + public open override /*1*/ /*fake_override*/ fun printStackTrace(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintStream!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun printStackTrace(/*0*/ s: java.io.PrintWriter!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun setStackTrace(/*0*/ stackTrace: kotlin.Array<(out) java.lang.StackTraceElement!>!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 7d7b7a1e30d..3d07c4ae0a7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -3266,16 +3266,31 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts.kt"); } + @TestMetadata("correctSmartcasts_after.kt") + public void testCorrectSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt"); + } + @TestMetadata("falseNegativeSmartcasts.kt") public void testFalseNegativeSmartcasts() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts.kt"); } + @TestMetadata("falseNegativeSmartcasts_after.kt") + public void testFalseNegativeSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt"); + } + @TestMetadata("falsePositiveSmartcasts.kt") public void testFalsePositiveSmartcasts() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts.kt"); } + @TestMetadata("falsePositiveSmartcasts_after.kt") + public void testFalsePositiveSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt"); + } + @TestMetadata("tryExpression.kt") public void testTryExpression() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/tryExpression.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 5d0ff885187..14ffaffe3b5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -3266,16 +3266,31 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts.kt"); } + @TestMetadata("correctSmartcasts_after.kt") + public void testCorrectSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/correctSmartcasts_after.kt"); + } + @TestMetadata("falseNegativeSmartcasts.kt") public void testFalseNegativeSmartcasts() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts.kt"); } + @TestMetadata("falseNegativeSmartcasts_after.kt") + public void testFalseNegativeSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falseNegativeSmartcasts_after.kt"); + } + @TestMetadata("falsePositiveSmartcasts.kt") public void testFalsePositiveSmartcasts() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts.kt"); } + @TestMetadata("falsePositiveSmartcasts_after.kt") + public void testFalsePositiveSmartcasts_after() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/falsePositiveSmartcasts_after.kt"); + } + @TestMetadata("tryExpression.kt") public void testTryExpression() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/tryCatch/tryExpression.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 050ede35d7e..cc02fa025e7 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -119,6 +119,9 @@ enum class LanguageFeature( SamConversionForKotlinFunctions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), + // can be used only with NewInference feature + NewDataFlowForTryExpressions(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), + InlineClasses(sinceVersion = KOTLIN_1_3, defaultState = State.ENABLED_WITH_WARNING, kind = UNSTABLE_FEATURE), ContractsOnCallsWithImplicitReceiver(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED),