Properly calculate safe call receivers

This commit is contained in:
Michael Bogdanov
2016-10-01 14:55:44 +03:00
committed by Dmitry Petrov
parent bc6f691405
commit e543972dad
6 changed files with 40 additions and 17 deletions
@@ -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}")
}
@@ -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 {
@@ -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 '<get-p>() 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 '<set-p>(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 '<get-p>() 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
+7 -1
View File
@@ -12,4 +12,10 @@ fun test4(x: Ref?) {
x?.value = 0
}
fun IHost.test5(s: String?) = s?.extLength()
fun IHost.test5(s: String?) = s?.extLength()
fun Int.foo() = 239
fun box() {
42?.foo()
}
+20
View File
@@ -107,3 +107,23 @@ FILE /safeCalls.kt
then: CALL 'extLength() on String: Int' type=kotlin.Int origin=null
$this: GET_VAR '<receiver: test5(String?) on IHost: Int?>' 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
@@ -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