diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index 68862d32c3e..3c55fe42d4a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -226,6 +226,22 @@ public class DataFlowAnalyzer { } } + // For cases like: + // fun bar(x: Any) {} + // fun foo(x: T) { + // if (x != null) { + // bar(x) // Should be allowed with smart cast + // } + // } + // + // It doesn't handled by upper code with getPossibleTypes because smart cast of T after `x != null` is still has same type T. + // But at the same time we're sure that `x` can't be null and just check for such cases manually + if (!c.dataFlowInfo.getNullability(dataFlowValue).canBeNull() + && JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, TypeUtils.makeNullable(c.expectedType))) { + smartCastManager.recordCastOrError(expression, expressionType, c.trace, dataFlowValue.isPredictable(), false); + return expressionType; + } + return null; } diff --git a/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.kt b/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.kt new file mode 100644 index 00000000000..b4497d20f89 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.kt @@ -0,0 +1,49 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION,-UNUSED_VARIABLE,-UNUSED_PARAMETER,-ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE,-UNUSED_VALUE + +fun bar1(x: T) {} +fun bar2(x: CharSequence) {} +fun bar3(x: String) {} + +fun foo(x: T) { + var y1: CharSequence = "" + var y2: String = "" + if (x != null) { + if (x != null) {} + + y1 = x + y2 = x + + bar1(x) + bar2(x) + bar3(x) + } + + if (x is String) { + y1 = x + y2 = x + + bar1(x) + bar2(x) + bar3(x) + } + + if (x is CharSequence) { + y1 = x + y2 = x + + bar1(x) + bar2(x) + bar3(x) + } + + if (1 == 1) { + val y = x!! + bar1(x) + bar2(x) + bar3(x) + + bar1(y) + bar2(y) + bar3(y) + } +} diff --git a/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.txt b/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.txt new file mode 100644 index 00000000000..b36313af984 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.txt @@ -0,0 +1,6 @@ +package + +internal fun bar1(/*0*/ x: T): kotlin.Unit +internal fun bar2(/*0*/ x: kotlin.CharSequence): kotlin.Unit +internal fun bar3(/*0*/ x: kotlin.String): kotlin.Unit +internal fun foo(/*0*/ x: T): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/generics/nullability/tpInBounds.kt b/compiler/testData/diagnostics/tests/generics/nullability/tpInBounds.kt index 7b56c9c09fd..c5c0103a568 100644 --- a/compiler/testData/diagnostics/tests/generics/nullability/tpInBounds.kt +++ b/compiler/testData/diagnostics/tests/generics/nullability/tpInBounds.kt @@ -28,9 +28,8 @@ class A { t = y - // Could be smart-cast if (y != null) { - t = y + t = y } if (tN != null) { diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index dec043093b3..88631817c94 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -6167,6 +6167,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("smartCastsValueArgument.kt") + public void testSmartCastsValueArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/nullability/smartCastsValueArgument.kt"); + doTest(fileName); + } + @TestMetadata("tpBoundsViolation.kt") public void testTpBoundsViolation() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/nullability/tpBoundsViolation.kt");