From a4b005fd5d2a52f31bfd76528d4c74d8986f54e4 Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 19 Dec 2019 11:15:43 +0100 Subject: [PATCH] PSI2IR: generate field writes for all val property assignments Assuming the frontend is correct, and it hopefully is, all of them are initializations even if not done in the owner class directly. --- .../psi2ir/generators/AssignmentGenerator.kt | 22 ++-------- .../contracts/propertyInitialization.kt | 3 +- .../testData/ir/irText/classes/initVal.kt | 8 ++++ .../testData/ir/irText/classes/initVal.txt | 41 +++++++++++++++++++ 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt index c581373c03f..d0681083c7a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/AssignmentGenerator.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irTemporary import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicOperatorExpressionImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* @@ -39,7 +38,6 @@ import org.jetbrains.kotlin.resolve.PropertyImportedFromObject import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic -import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver import org.jetbrains.kotlin.types.KotlinType class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) { @@ -277,16 +275,10 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen isAssignmentReceiver = isAssignmentStatement ) ) - isValInitializationInConstructor(descriptor, resolvedCall) -> { - val thisClass = getThisClass() - val thisAsReceiverParameter = thisClass.thisAsReceiverParameter - val thisType = thisAsReceiverParameter.type.toIrType() - val irThis = IrGetValueImpl( - ktLeft.startOffsetSkippingComments, ktLeft.endOffset, - thisType, - context.symbolTable.referenceValueParameter(thisAsReceiverParameter) - ) - createBackingFieldLValue(ktLeft, descriptor, RematerializableValue(irThis), null) + origin == IrStatementOrigin.EQ && !descriptor.isVar -> { + // An assignment to a val property can only be its initialization in the constructor. + val receiver = resolvedCall.dispatchReceiver ?: descriptor.dispatchReceiverParameter?.value + createBackingFieldLValue(ktLeft, descriptor, statementGenerator.generateReceiverOrNull(ktLeft, receiver), null) } else -> { val propertyReceiver = statementGenerator.generateCallReceiver( @@ -356,12 +348,6 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen ) } - 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 - private fun getThisClass(): ClassDescriptor { val scopeOwner = statementGenerator.scopeOwner return when (scopeOwner) { diff --git a/compiler/testData/codegen/boxInline/contracts/propertyInitialization.kt b/compiler/testData/codegen/boxInline/contracts/propertyInitialization.kt index 86ae6f5e4b4..73c3b13bc34 100644 --- a/compiler/testData/codegen/boxInline/contracts/propertyInitialization.kt +++ b/compiler/testData/codegen/boxInline/contracts/propertyInitialization.kt @@ -1,6 +1,5 @@ // !USE_EXPERIMENTAL: kotlin.contracts.ExperimentalContracts -// IGNORE_BACKEND: JVM_IR, JS_IR, NATIVE -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR +// IGNORE_BACKEND: NATIVE // FILE: 1.kt diff --git a/compiler/testData/ir/irText/classes/initVal.kt b/compiler/testData/ir/irText/classes/initVal.kt index 5b47f01e4a6..f5b4b27a0c6 100644 --- a/compiler/testData/ir/irText/classes/initVal.kt +++ b/compiler/testData/ir/irText/classes/initVal.kt @@ -12,3 +12,11 @@ class TestInitValInInitBlock { } } +class TestInitValInLambdaCalledOnce { + val x: Int + init { + 1.run { + x = 0 + } + } +} diff --git a/compiler/testData/ir/irText/classes/initVal.txt b/compiler/testData/ir/irText/classes/initVal.txt index 688c1dcc903..39dbe3d6f62 100644 --- a/compiler/testData/ir/irText/classes/initVal.txt +++ b/compiler/testData/ir/irText/classes/initVal.txt @@ -93,3 +93,44 @@ FILE fqName: fileName:/initVal.kt overridden: public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any + CLASS CLASS name:TestInitValInLambdaCalledOnce modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.TestInitValInLambdaCalledOnce + CONSTRUCTOR visibility:public <> () returnType:.TestInitValInLambdaCalledOnce [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:TestInitValInLambdaCalledOnce modality:FINAL visibility:public superTypes:[kotlin.Any]' + PROPERTY name:x visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final] + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:.TestInitValInLambdaCalledOnce) returnType:kotlin.Int + correspondingProperty: PROPERTY name:x visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:.TestInitValInLambdaCalledOnce + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.Int declared in .TestInitValInLambdaCalledOnce' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': .TestInitValInLambdaCalledOnce declared in .TestInitValInLambdaCalledOnce.' type=.TestInitValInLambdaCalledOnce origin=null + ANONYMOUS_INITIALIZER isStatic=false + BLOCK_BODY + CALL 'public final fun run (block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.run [inline] declared in kotlin' type=kotlin.Unit origin=null + : kotlin.Int + : kotlin.Unit + $receiver: CONST Int type=kotlin.Int value=1 + block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:kotlin.Int) returnType:kotlin.Unit + $receiver: VALUE_PARAMETER name: type:kotlin.Int + BLOCK_BODY + SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:x type:kotlin.Int visibility:private [final]' type=kotlin.Unit origin=null + receiver: GET_VAR ': .TestInitValInLambdaCalledOnce declared in .TestInitValInLambdaCalledOnce' type=.TestInitValInLambdaCalledOnce origin=null + value: CONST Int type=kotlin.Int value=0 + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any