K2: Resolve safe call receiver in ReceiverResolution mode
For safe calls under PCLA, we should behave in the same way as
for regular qualified calls, i.e. we should semi-fix type variables
when necessary
In PCLAInferenceSession semi-fixation only runs for ReceiverResolution.
Then, it's necessary to apply integerLiteralAndOperatorApproximationTransformer
because by default ReceiverResolution leaves them not-approximated,
but constants/ILT evaluation didn't work before and is not supposed
to work for safe calls.
^KT-69170 Fixed
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
index 77ce975..c38a15d 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
@@ -404,7 +404,9 @@
whileAnalysing(session, safeCallExpression) {
withContainingSafeCallExpression(safeCallExpression) {
safeCallExpression.transformAnnotations(this, ResolutionMode.ContextIndependent)
- safeCallExpression.transformReceiver(this, ResolutionMode.ContextIndependent)
+
+ safeCallExpression.transformReceiver(this, ResolutionMode.ReceiverResolution)
+ safeCallExpression.transformReceiver(components.integerLiteralAndOperatorApproximationTransformer, null)
val receiver = safeCallExpression.receiver
diff --git a/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/memberScope.fir.kt b/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/memberScope.fir.kt
index bea3b71..f427f62 100644
--- a/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/memberScope.fir.kt
+++ b/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/memberScope.fir.kt
@@ -20,50 +20,50 @@
val ret1 = build {
emit(1)
emit(null)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
+ get()?.test()
+ get()?.test2()
get().test2()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.hashCode()
- get()?.<!NONE_APPLICABLE!>equals<!>(1)
+ get()?.hashCode()
+ get()?.equals(1)
// there is `String?.equals` extension
get()<!UNSAFE_CALL!>.<!>equals("")
}
val ret2 = build {
emit(1)
emit(null)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
+ get()?.test()
+ get()?.test2()
get().test2()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.hashCode()
- get()?.<!NONE_APPLICABLE!>equals<!>(1)
+ get()?.hashCode()
+ get()?.equals(1)
val x = get()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>?.hashCode()
- x?.<!NONE_APPLICABLE!>equals<!>(1)
+ x?.hashCode()
+ x?.equals(1)
x<!UNSAFE_CALL!>.<!>equals("")
}
val ret3 = build {
emit(1)
emit(null)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
+ get()?.test()
+ get()?.test2()
get().test2()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.hashCode()
- get()?.<!NONE_APPLICABLE!>equals<!>(1)
+ get()?.hashCode()
+ get()?.equals(1)
val x = get()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>?.hashCode()
- x?.<!NONE_APPLICABLE!>equals<!>(1)
+ x?.hashCode()
+ x?.equals(1)
if (get() == null) {}
if (get() === null) {}
if (x != null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>hashCode()
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1)
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>hashCode()
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>equals(1)
x.equals("")
x.hashCode()
x.toString()
x.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>test2()
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>test2()
x.test2()
}
@@ -160,28 +160,28 @@
val ret41 = build {
emit(1)
emit(null)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
+ get()?.test()
+ get()?.test2()
get().test2()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.hashCode()
- get()?.<!NONE_APPLICABLE!>equals<!>(1)
+ get()?.hashCode()
+ get()?.equals(1)
val x = get()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>?.hashCode()
- x?.<!NONE_APPLICABLE!>equals<!>(1)
+ x?.hashCode()
+ x?.equals(1)
if (get() == null) {}
if (get() === null) {}
if (x == null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>hashCode()
+ x?.hashCode()
}
if (x == null) {
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1)
+ x?.equals(1)
}
if (x == null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>test2()
+ x?.test2()
}
if (x == null) {
@@ -189,15 +189,15 @@
}
if (x === null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>hashCode()
+ x?.hashCode()
}
if (x === null) {
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1)
+ x?.equals(1)
}
if (x === null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>test2()
+ x?.test2()
}
if (x === null) {
@@ -290,22 +290,22 @@
val ret51 = build {
emit(1)
emit(null)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.test2()
+ get()?.test()
+ get()?.test2()
get().test2()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!>?.hashCode()
- get()?.<!NONE_APPLICABLE!>equals<!>(1)
+ get()?.hashCode()
+ get()?.equals(1)
val x = get()
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!>?.hashCode()
- x?.<!NONE_APPLICABLE!>equals<!>(1)
+ x?.hashCode()
+ x?.equals(1)
if (get() == null) {}
if (get() === null) {}
if (x == null) {
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>hashCode()
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>(1)
- <!BUILDER_INFERENCE_STUB_RECEIVER!>x<!><!UNNECESSARY_SAFE_CALL!>?.<!>test2()
+ x?.hashCode()
+ x?.equals(1)
+ x?.test2()
x.test2()
}
diff --git a/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/nullability.fir.kt b/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/nullability.fir.kt
index 9fda198..fb033d6 100644
--- a/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/nullability.fir.kt
+++ b/compiler/testData/diagnostics/tests/inference/pcla/stubTypes/nullability.fir.kt
@@ -25,27 +25,27 @@
fun test(a: String?) {
val ret1 = build {
emit(1)
- get()<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""
}
val ret2 = build2 {
emit(1)
- get()<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""
}
val ret3 = build3 {
emit(1)
- get()<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
- x<!UNNECESSARY_SAFE_CALL!>?.<!><!NONE_APPLICABLE!>equals<!>("")
+ x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""