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,
|
||||
ktLeft: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>
|
||||
): AssignmentReceiver {
|
||||
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
|
||||
val thisClass = getThisClass()
|
||||
val irThis = IrGetValueImpl(ktLeft.startOffset, ktLeft.endOffset, thisClass.thisAsReceiverParameter)
|
||||
return BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor,
|
||||
RematerializableValue(irThis), null)
|
||||
}
|
||||
): AssignmentReceiver =
|
||||
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
|
||||
val thisClass = getThisClass()
|
||||
val irThis = IrGetValueImpl(ktLeft.startOffset, ktLeft.endOffset, thisClass.thisAsReceiverParameter)
|
||||
|
||||
val propertyReceiver = statementGenerator.generateCallReceiver(
|
||||
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||
isSafe = resolvedCall.call.isSafeCall(),
|
||||
isAssignmentReceiver = true)
|
||||
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor,
|
||||
RematerializableValue(irThis), null)
|
||||
}
|
||||
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,
|
||||
getTypeArguments(resolvedCall), propertyReceiver, superQualifier)
|
||||
}
|
||||
SimplePropertyLValue(context, scope, ktLeft.startOffset, ktLeft.endOffset, origin, descriptor,
|
||||
getTypeArguments(resolvedCall), propertyReceiver, superQualifier)
|
||||
}
|
||||
|
||||
private fun isValInitializationInConstructor(descriptor: PropertyDescriptor, resolvedCall: ResolvedCall<*>): Boolean =
|
||||
!descriptor.isVar &&
|
||||
descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||
statementGenerator.scopeOwner.let { it is ConstructorDescriptor || it is ClassDescriptor } &&
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("kt16904.kt")
|
||||
public void testKt16904() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/kt16904.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("literals.kt")
|
||||
public void testLiterals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/literals.kt");
|
||||
|
||||
Reference in New Issue
Block a user