From 96a7febd09f94a58530ff6ba3a0303737abbafa0 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 1 Mar 2016 17:10:15 +0300 Subject: [PATCH] Smart cast is performed now inside 'x as? Type ?: return' safe as / elvis combination #KT-10992 Fixed --- .../BasicExpressionTypingVisitor.java | 24 +++++++++++++++++++ .../diagnostics/tests/smartCasts/safeAs.kt | 17 +++++++++++++ .../diagnostics/tests/smartCasts/safeAs.txt | 5 ++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++++ 4 files changed, 52 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/smartCasts/safeAs.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/safeAs.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 50a1a7c4c5e..59752209134 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -1304,6 +1304,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { // left argument is considered not-null if it's not-null also in right part or if we have jump in right part if (jumpInRight || !rightDataFlowInfo.getPredictableNullability(leftValue).canBeNull()) { dataFlowInfo = dataFlowInfo.disequate(leftValue, nullValue); + if (left instanceof KtBinaryExpressionWithTypeRHS) { + dataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, dataFlowInfo, context); + } } DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, type, context); dataFlowInfo = dataFlowInfo.assign(resultValue, leftValue).disequate(resultValue, nullValue); @@ -1331,6 +1334,27 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.dataFlowInfo); } + @NotNull + private static DataFlowInfo establishSubtypingForTypeRHS( + @NotNull KtBinaryExpressionWithTypeRHS left, + @NotNull DataFlowInfo dataFlowInfo, + @NotNull ExpressionTypingContext context + ) { + IElementType operationType = left.getOperationReference().getReferencedNameElementType(); + if (operationType == AS_SAFE) { + KtExpression underSafeAs = left.getLeft(); + KotlinType underSafeAsType = context.trace.getType(underSafeAs); + if (underSafeAsType != null) { + DataFlowValue underSafeAsValue = createDataFlowValue(underSafeAs, underSafeAsType, context); + KotlinType targetType = context.trace.get(BindingContext.TYPE, left.getRight()); + if (targetType != null) { + return dataFlowInfo.establishSubtyping(underSafeAsValue, targetType); + } + } + } + return dataFlowInfo; + } + @NotNull public KotlinTypeInfo checkInExpression( @NotNull KtElement callElement, diff --git a/compiler/testData/diagnostics/tests/smartCasts/safeAs.kt b/compiler/testData/diagnostics/tests/smartCasts/safeAs.kt new file mode 100644 index 00000000000..50250d74c35 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/safeAs.kt @@ -0,0 +1,17 @@ +// See also KT-10992: we should have no errors for all unsafe hashCode() calls + +fun foo(arg: Any?) { + val x = arg as? Any ?: return + arg.hashCode() + x.hashCode() +} + +fun bar(arg: Any?) { + arg as? Any ?: return + arg.hashCode() +} + +fun gav(arg: Any?) { + arg as? String ?: return + arg.length +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/safeAs.txt b/compiler/testData/diagnostics/tests/smartCasts/safeAs.txt new file mode 100644 index 00000000000..cc247d832be --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/safeAs.txt @@ -0,0 +1,5 @@ +package + +public fun bar(/*0*/ arg: kotlin.Any?): kotlin.Unit +public fun foo(/*0*/ arg: kotlin.Any?): kotlin.Unit +public fun gav(/*0*/ arg: kotlin.Any?): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 7dd52e6d963..84912ad796d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16455,6 +16455,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("safeAs.kt") + public void testSafeAs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/safeAs.kt"); + doTest(fileName); + } + @TestMetadata("shortIfExprNotNull.kt") public void testShortIfExprNotNull() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/shortIfExprNotNull.kt");