KT-16904 Wrong IR when applying some operators to superclass properties in constructor
Use property accessors for assignment generation for inherited properties in constructor.
This commit is contained in:
+17
-15
@@ -131,27 +131,29 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
|||||||
origin: IrStatementOrigin,
|
origin: IrStatementOrigin,
|
||||||
ktLeft: KtExpression,
|
ktLeft: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>
|
resolvedCall: ResolvedCall<*>
|
||||||
): AssignmentReceiver {
|
): AssignmentReceiver =
|
||||||
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
|
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
|
||||||
val thisClass = getThisClass()
|
val thisClass = getThisClass()
|
||||||
val irThis = IrGetValueImpl(ktLeft.startOffset, ktLeft.endOffset, thisClass.thisAsReceiverParameter)
|
val irThis = IrGetValueImpl(ktLeft.startOffset, ktLeft.endOffset, thisClass.thisAsReceiverParameter)
|
||||||
return BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor,
|
|
||||||
RematerializableValue(irThis), null)
|
|
||||||
}
|
|
||||||
|
|
||||||
val propertyReceiver = statementGenerator.generateCallReceiver(
|
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor,
|
||||||
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
RematerializableValue(irThis), null)
|
||||||
isSafe = resolvedCall.call.isSafeCall(),
|
}
|
||||||
isAssignmentReceiver = true)
|
else {
|
||||||
|
val propertyReceiver = statementGenerator.generateCallReceiver(
|
||||||
|
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||||
|
isSafe = resolvedCall.call.isSafeCall(),
|
||||||
|
isAssignmentReceiver = true)
|
||||||
|
|
||||||
val superQualifier = getSuperQualifier(resolvedCall)
|
val superQualifier = getSuperQualifier(resolvedCall)
|
||||||
|
|
||||||
return SimplePropertyLValue(context, scope, ktLeft.startOffset, ktLeft.endOffset, origin, descriptor,
|
SimplePropertyLValue(context, scope, ktLeft.startOffset, ktLeft.endOffset, origin, descriptor,
|
||||||
getTypeArguments(resolvedCall), propertyReceiver, superQualifier)
|
getTypeArguments(resolvedCall), propertyReceiver, superQualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isValInitializationInConstructor(descriptor: PropertyDescriptor, resolvedCall: ResolvedCall<*>): Boolean =
|
private fun isValInitializationInConstructor(descriptor: PropertyDescriptor, resolvedCall: ResolvedCall<*>): Boolean =
|
||||||
!descriptor.isVar &&
|
!descriptor.isVar &&
|
||||||
|
descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||||
statementGenerator.scopeOwner.let { it is ConstructorDescriptor || it is ClassDescriptor } &&
|
statementGenerator.scopeOwner.let { it is ConstructorDescriptor || it is ClassDescriptor } &&
|
||||||
resolvedCall.dispatchReceiver is ThisClassReceiver
|
resolvedCall.dispatchReceiver is ThisClassReceiver
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// FILE: J.java
|
||||||
|
|
||||||
|
public class J {
|
||||||
|
public int field = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: kt16904.kt
|
||||||
|
|
||||||
|
abstract class A {
|
||||||
|
val x = B()
|
||||||
|
var y = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
operator fun plusAssign(x: Int) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test1 : A {
|
||||||
|
constructor() {
|
||||||
|
x += 42
|
||||||
|
y += 42
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test2 : J() {
|
||||||
|
init {
|
||||||
|
field = 42
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
FILE /kt16904.kt
|
||||||
|
CLASS CLASS A
|
||||||
|
CONSTRUCTOR public constructor A()
|
||||||
|
BLOCK_BODY
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||||
|
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||||
|
PROPERTY public final val x: B
|
||||||
|
FIELD PROPERTY_BACKING_FIELD public final val x: B
|
||||||
|
EXPRESSION_BODY
|
||||||
|
CALL 'constructor B()' type=B origin=null
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-x>(): B
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-x>(): B'
|
||||||
|
GET_FIELD 'x: B' type=B origin=null
|
||||||
|
receiver: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
PROPERTY public final var y: kotlin.Int
|
||||||
|
FIELD PROPERTY_BACKING_FIELD public final var y: kotlin.Int
|
||||||
|
EXPRESSION_BODY
|
||||||
|
CONST Int type=kotlin.Int value='0'
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-y>(): kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-y>(): Int'
|
||||||
|
GET_FIELD 'y: Int' type=kotlin.Int origin=null
|
||||||
|
receiver: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <set-y>(<set-?>: kotlin.Int): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
SET_FIELD 'y: Int' type=kotlin.Unit origin=null
|
||||||
|
receiver: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
value: GET_VAR 'value-parameter <set-?>: Int' type=kotlin.Int origin=null
|
||||||
|
CLASS CLASS B
|
||||||
|
CONSTRUCTOR public constructor B()
|
||||||
|
BLOCK_BODY
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||||
|
INSTANCE_INITIALIZER_CALL classDescriptor='B'
|
||||||
|
FUN public final operator fun plusAssign(x: kotlin.Int): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
CLASS CLASS Test1
|
||||||
|
CONSTRUCTOR public constructor Test1()
|
||||||
|
BLOCK_BODY
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'constructor A()'
|
||||||
|
INSTANCE_INITIALIZER_CALL classDescriptor='Test1'
|
||||||
|
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||||
|
VAR IR_TEMPORARY_VARIABLE val tmp0_this: Test1
|
||||||
|
GET_VAR '<receiver: Test1>' type=Test1 origin=null
|
||||||
|
CALL 'plusAssign(Int): Unit' type=kotlin.Unit origin=PLUSEQ
|
||||||
|
$this: CALL '<get-x>(): B' type=B origin=PLUSEQ
|
||||||
|
$this: GET_VAR 'tmp0_this: Test1' type=Test1 origin=null
|
||||||
|
x: CONST Int type=kotlin.Int value='42'
|
||||||
|
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||||
|
VAR IR_TEMPORARY_VARIABLE val tmp1_this: Test1
|
||||||
|
GET_VAR '<receiver: Test1>' type=Test1 origin=null
|
||||||
|
CALL '<set-y>(Int): Unit' type=kotlin.Unit origin=PLUSEQ
|
||||||
|
$this: GET_VAR 'tmp1_this: Test1' type=Test1 origin=null
|
||||||
|
<set-?>: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||||
|
$this: CALL '<get-y>(): Int' type=kotlin.Int origin=PLUSEQ
|
||||||
|
$this: GET_VAR 'tmp1_this: Test1' type=Test1 origin=null
|
||||||
|
other: CONST Int type=kotlin.Int value='42'
|
||||||
|
CLASS CLASS Test2
|
||||||
|
CONSTRUCTOR public constructor Test2()
|
||||||
|
BLOCK_BODY
|
||||||
|
DELEGATING_CONSTRUCTOR_CALL 'constructor J()'
|
||||||
|
INSTANCE_INITIALIZER_CALL classDescriptor='Test2'
|
||||||
|
ANONYMOUS_INITIALIZER Test2
|
||||||
|
BLOCK_BODY
|
||||||
|
SET_FIELD 'field: Int' type=kotlin.Unit origin=EQ
|
||||||
|
receiver: GET_VAR '<receiver: Test2>' type=Test2 origin=null
|
||||||
|
value: CONST Int type=kotlin.Int value='42'
|
||||||
@@ -602,6 +602,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt16904.kt")
|
||||||
|
public void testKt16904() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/kt16904.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("literals.kt")
|
@TestMetadata("literals.kt")
|
||||||
public void testLiterals() throws Exception {
|
public void testLiterals() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/literals.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/literals.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user