diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index a2f2a87bfcc..9d72351a27e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -86,12 +86,9 @@ fun StatementGenerator.generateCallReceiver( return when { !isSafe -> SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue) - extensionReceiverValue != null -> + extensionReceiverValue != null || dispatchReceiverValue != null-> SafeCallReceiver(this, ktDefaultElement.startOffset, ktDefaultElement.endOffset, - extensionReceiverValue.load(), dispatchReceiverValue, isAssignmentReceiver) - dispatchReceiverValue != null -> - SafeCallReceiver(this, ktDefaultElement.startOffset, ktDefaultElement.endOffset, - dispatchReceiverValue.load(), null, isAssignmentReceiver) + extensionReceiverValue, dispatchReceiverValue, isAssignmentReceiver) else -> throw AssertionError("Safe call should have an explicit receiver: ${ktDefaultElement.text}") } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt index 3204fd544ba..5deef4d4100 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/SafeCallReceiver.kt @@ -31,18 +31,18 @@ class SafeCallReceiver( val generator: GeneratorWithScope, val startOffset: Int, val endOffset: Int, - val explicitReceiver: IrExpression, - val implicitDispatchReceiverValue: IntermediateValue?, + val extensionReceiver: IntermediateValue?, + val dispatchReceiver: IntermediateValue?, val isAssignmentReceiver: Boolean ) : CallReceiver { override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { - val irTmp = generator.scope.createTemporaryVariable(explicitReceiver, "safe_receiver") + val irTmp = generator.scope.createTemporaryVariable(extensionReceiver?.load() ?: dispatchReceiver!!.load(), "safe_receiver") val safeReceiverValue = VariableLValue(irTmp) - val dispatchReceiverValue: IntermediateValue + val dispatchReceiverValue: IntermediateValue? val extensionReceiverValue: IntermediateValue? - if (implicitDispatchReceiverValue != null) { - dispatchReceiverValue = implicitDispatchReceiverValue + if (extensionReceiver != null) { + dispatchReceiverValue = dispatchReceiver extensionReceiverValue = safeReceiverValue } else { diff --git a/compiler/testData/ir/irText/expressions/safeCallWithIncrementDecrement.txt b/compiler/testData/ir/irText/expressions/safeCallWithIncrementDecrement.txt index 70bf2abd4df..531ca051a14 100644 --- a/compiler/testData/ir/irText/expressions/safeCallWithIncrementDecrement.txt +++ b/compiler/testData/ir/irText/expressions/safeCallWithIncrementDecrement.txt @@ -49,14 +49,14 @@ FILE /safeCallWithIncrementDecrement.kt if: CONST Boolean type=kotlin.Boolean value='true' then: TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit BLOCK type=kotlin.Int origin=POSTFIX_INCR - VAR IR_TEMPORARY_VARIABLE val tmp1_this: test.C? + VAR IR_TEMPORARY_VARIABLE val tmp1_receiver: test.C? GET_VAR 'tmp0_safe_receiver: C?' type=test.C? origin=null BLOCK type=kotlin.Int origin=POSTFIX_INCR VAR IR_TEMPORARY_VARIABLE val tmp2: kotlin.Int CALL '() on C?: Int' type=kotlin.Int origin=POSTFIX_INCR - $this: GET_VAR 'tmp1_this: C?' type=test.C? origin=null + $receiver: GET_VAR 'tmp1_receiver: C?' type=test.C? origin=null CALL '(Int) on C?: Unit' type=kotlin.Unit origin=POSTFIX_INCR - $this: GET_VAR 'tmp1_this: C?' type=test.C? origin=null + $receiver: GET_VAR 'tmp1_receiver: C?' type=test.C? origin=null value: CALL 'inc() on Int?: Int?' type=kotlin.Int? origin=POSTFIX_INCR $receiver: GET_VAR 'tmp2: Int' type=kotlin.Int origin=null GET_VAR 'tmp2: Int' type=kotlin.Int origin=null @@ -77,7 +77,7 @@ FILE /safeCallWithIncrementDecrement.kt BRANCH if: CONST Boolean type=kotlin.Boolean value='true' then: CALL '() on C?: Int' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR 'tmp0_safe_receiver: C?' type=test.C? origin=null + $receiver: GET_VAR 'tmp0_safe_receiver: C?' type=test.C? origin=null VAR IR_TEMPORARY_VARIABLE val tmp4_index0: kotlin.Int CONST Int type=kotlin.Int value='0' VAR IR_TEMPORARY_VARIABLE val tmp5: kotlin.Int diff --git a/compiler/testData/ir/irText/expressions/safeCalls.kt b/compiler/testData/ir/irText/expressions/safeCalls.kt index ddebcb0c231..82943638a94 100644 --- a/compiler/testData/ir/irText/expressions/safeCalls.kt +++ b/compiler/testData/ir/irText/expressions/safeCalls.kt @@ -12,4 +12,10 @@ fun test4(x: Ref?) { x?.value = 0 } -fun IHost.test5(s: String?) = s?.extLength() \ No newline at end of file +fun IHost.test5(s: String?) = s?.extLength() + +fun Int.foo() = 239 + +fun box() { + 42?.foo() +} diff --git a/compiler/testData/ir/irText/expressions/safeCalls.txt b/compiler/testData/ir/irText/expressions/safeCalls.txt index ecf90934606..a93f48657ea 100644 --- a/compiler/testData/ir/irText/expressions/safeCalls.txt +++ b/compiler/testData/ir/irText/expressions/safeCalls.txt @@ -107,3 +107,23 @@ FILE /safeCalls.kt then: CALL 'extLength() on String: Int' type=kotlin.Int origin=null $this: GET_VAR '' type=IHost origin=null $receiver: GET_VAR 'tmp0_safe_receiver: String?' type=kotlin.String? origin=null + FUN public fun kotlin.Int.foo(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='foo() on Int: Int' + CONST Int type=kotlin.Int value='239' + FUN public fun box(): kotlin.Unit + BLOCK_BODY + TYPE_OP origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Int? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE val tmp0_safe_receiver: kotlin.Int + CONST Int type=kotlin.Int value='42' + WHEN type=kotlin.Int? origin=SAFE_CALL + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'tmp0_safe_receiver: Int' type=kotlin.Int origin=null + arg1: CONST Null type=kotlin.Nothing? value='null' + then: CONST Null type=kotlin.Nothing? value='null' + BRANCH + if: CONST Boolean type=kotlin.Boolean value='true' + then: CALL 'foo() on Int: Int' type=kotlin.Int origin=null + $receiver: GET_VAR 'tmp0_safe_receiver: Int' type=kotlin.Int origin=null diff --git a/compiler/testData/ir/irText/expressions/variableAsFunctionCall.txt b/compiler/testData/ir/irText/expressions/variableAsFunctionCall.txt index 8572fd1f240..7424d401249 100644 --- a/compiler/testData/ir/irText/expressions/variableAsFunctionCall.txt +++ b/compiler/testData/ir/irText/expressions/variableAsFunctionCall.txt @@ -42,7 +42,7 @@ FILE /variableAsFunctionCall.kt BRANCH if: CONST Boolean type=kotlin.Boolean value='true' then: CALL 'k() on String: () -> String' type=() -> kotlin.String origin=null - $this: GET_VAR 'tmp0_safe_receiver: String?' type=kotlin.String? origin=null + $receiver: GET_VAR 'tmp0_safe_receiver: String?' type=kotlin.String? origin=null WHEN type=kotlin.String? origin=SAFE_CALL BRANCH if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ