From 504449f03eb3debc128abd4bc31dcba9b9b0dcf1 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Thu, 29 Jul 2021 18:52:36 +0000 Subject: [PATCH] FIR: Report UNSAFE_CALL instead of SMARTCAST_IMPOSSIBLE when smartcast to null. Currently the error message shows the expression is impossible to smartcast to the nullable type, which is nonsensical since it's already that type. --- .../resolve/smartcasts/nullability.dot | 55 +++++++++++++++++++ .../resolve/smartcasts/nullability.fir.txt | 8 +++ .../resolve/smartcasts/nullability.kt | 7 +++ .../fir/resolve/calls/ResolutionStages.kt | 1 + 4 files changed, 71 insertions(+) diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot index 3ef22d46e6d..85a4d35677c 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.dot @@ -1413,4 +1413,59 @@ digraph nullability_kt { 534 -> {535}; 535 -> {536}; + subgraph cluster_107 { + color=red + 537 [label="Enter function test_14" style="filled" fillcolor=red]; + subgraph cluster_108 { + color=blue + 538 [label="Enter block"]; + subgraph cluster_109 { + color=blue + 539 [label="Enter when"]; + subgraph cluster_110 { + color=blue + 540 [label="Enter when branch condition "]; + 541 [label="Access variable R|/q|"]; + 542 [label="Access variable R|/Q.data|"]; + 543 [label="Const: Null(null)"]; + 544 [label="Equality operator =="]; + 545 [label="Exit when branch condition"]; + } + 546 [label="Synthetic else branch"]; + 547 [label="Enter when branch result"]; + subgraph cluster_111 { + color=blue + 548 [label="Enter block"]; + 549 [label="Access variable R|/q|"]; + 550 [label="Access variable R|/Q.data|"]; + 551 [label="Access variable #"]; + 552 [label="Exit block"]; + } + 553 [label="Exit when branch result"]; + 554 [label="Exit when"]; + } + 555 [label="Exit block"]; + } + 556 [label="Exit function test_14" style="filled" fillcolor=red]; + } + 537 -> {538}; + 538 -> {539}; + 539 -> {540}; + 540 -> {541}; + 541 -> {542}; + 542 -> {543}; + 543 -> {544}; + 544 -> {545}; + 545 -> {547 546}; + 546 -> {554}; + 547 -> {548}; + 548 -> {549}; + 549 -> {550}; + 550 -> {551}; + 551 -> {552}; + 552 -> {553}; + 553 -> {554}; + 554 -> {555}; + 555 -> {556}; + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt index c9de93e9311..fd5cbd1012c 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.fir.txt @@ -232,3 +232,11 @@ FILE: nullability.kt } } + public final fun test_14(q: R|Q|): R|kotlin/Unit| { + when () { + ==(R|/q|.R|/Q.data|, Null(null)) -> { + R|/q|.R|/Q.data|.# + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt index 7347a02d70f..20fc39b20ad 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/nullability.kt @@ -175,3 +175,10 @@ fun test_13(q: QImplMutable?) { q.data.s.inc() // should be bad } } + +fun test_14(q: Q) { + // `q.data` is a property that has an open getter + if (q.data == null) { + q.data.s // should be UNSAFE_CALL and NOT SMARTCAST_IMPOSSIBLE + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index c7b180f6a16..02fa1997c05 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -116,6 +116,7 @@ object CheckDispatchReceiver : ResolutionStage() { (candidate.originScope as? FirUnstableSmartcastTypeScope)?.isSymbolFromUnstableSmartcast(candidate.symbol) == true if (explicitReceiverExpression is FirExpressionWithSmartcast && + explicitReceiverExpression !is FirExpressionWithSmartcastToNull && explicitReceiverExpression.smartcastStability != SmartcastStability.STABLE_VALUE && (isCandidateFromUnstableSmartcast || isReceiverNullable) ) {