From 3a4f6d8226fde6434600f94f0dd71b8790f100b8 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 18 Nov 2015 14:18:04 +0300 Subject: [PATCH] Smart cast impossible on when subject is no more recorded #KT-10061 Fixed --- .../types/expressions/DataFlowAnalyzer.java | 9 ++++----- .../PatternMatchingTypingVisitor.java | 17 +++++++++++------ .../tests/smartCasts/whenSubjectImpossible.kt | 10 ++++++++++ .../tests/smartCasts/whenSubjectImpossible.txt | 11 +++++++++++ .../smartCasts/whenSubjectImpossibleJava.kt | 11 +++++++++++ .../smartCasts/whenSubjectImpossibleJava.txt | 11 +++++++++++ .../checkers/DiagnosticsTestGenerated.java | 12 ++++++++++++ 7 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.txt 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 5ac5e896d7c..75b760c51f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -207,8 +207,8 @@ public class DataFlowAnalyzer { return expressionType; } - KotlinType possibleType = checkPossibleCast(expressionType, expression, c); - if (possibleType != null) return possibleType; + SmartCastResult castResult = checkPossibleCast(expressionType, expression, c); + if (castResult != null) return castResult.getResultType(); c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType)); if (hasError != null) hasError.set(true); @@ -245,15 +245,14 @@ public class DataFlowAnalyzer { } @Nullable - public KotlinType checkPossibleCast( + public SmartCastResult checkPossibleCast( @NotNull KotlinType expressionType, @NotNull KtExpression expression, @NotNull ResolutionContext c ) { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c); - SmartCastResult result = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false); - return result != null ? result.getResultType() : null; + return SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false); } public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java index bd16b42fd1c..91cb0d1314b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -25,13 +25,11 @@ import org.jetbrains.kotlin.cfg.WhenChecker; import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.DescriptorUtils; -import org.jetbrains.kotlin.resolve.PossiblyBareType; -import org.jetbrains.kotlin.resolve.TypeResolutionContext; +import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory; +import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastResult; import org.jetbrains.kotlin.resolve.calls.util.CallMaker; import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope; import org.jetbrains.kotlin.types.*; @@ -92,8 +90,15 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { subjectType = typeInfo.getType(); assert subjectType != null; if (TypeUtils.isNullableType(subjectType) && !WhenChecker.containsNullCase(expression, context.trace)) { - ExpressionTypingContext subjectContext = context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType)); - components.dataFlowAnalyzer.checkPossibleCast(subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext); + TemporaryBindingTrace trace = TemporaryBindingTrace.create(context.trace, "Temporary trace for when subject nullability"); + ExpressionTypingContext subjectContext = + context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType)).replaceBindingTrace(trace); + SmartCastResult castResult = components.dataFlowAnalyzer.checkPossibleCast( + subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext + ); + if (castResult != null && castResult.isCorrect()) { + trace.commit(); + } } context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()); } diff --git a/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt new file mode 100644 index 00000000000..a679b102d71 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt @@ -0,0 +1,10 @@ +// See KT-10061 + +class My { + val x: Int? get() = 42 +} + +fun foo(my: My) { + my.x!! + when (my.x) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.txt b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.txt new file mode 100644 index 00000000000..994d0e4e8ec --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.txt @@ -0,0 +1,11 @@ +package + +public fun foo(/*0*/ my: My): kotlin.Unit + +public final class My { + public constructor My() + public final val x: kotlin.Int? + 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/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt new file mode 100644 index 00000000000..955e071a1d8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt @@ -0,0 +1,11 @@ +// See KT-10061 +// FILE: My.java +public class My { + String getSomething() { return "xyz"; } +} + +// FILE: My.kt +fun foo(my: My) { + my.something!! + when (my.something) { } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.txt b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.txt new file mode 100644 index 00000000000..d230ea269e5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.txt @@ -0,0 +1,11 @@ +package + +public fun foo(/*0*/ my: My): kotlin.Unit + +public open class My { + public constructor My() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public/*package*/ open fun getSomething(): kotlin.String! + 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 036356135ea..cd890dd1ebe 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -14922,6 +14922,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("whenSubjectImpossible.kt") + public void testWhenSubjectImpossible() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt"); + doTest(fileName); + } + + @TestMetadata("whenSubjectImpossibleJava.kt") + public void testWhenSubjectImpossibleJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt"); + doTest(fileName); + } + @TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)