diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt index a7d0fb88f6f..82b6804274a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DelegatedPropertyGenerator.kt @@ -22,12 +22,10 @@ import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* -import org.jetbrains.kotlin.ir.descriptors.IrLocalDelegatedPropertyDelegateDescriptor -import org.jetbrains.kotlin.ir.descriptors.IrLocalDelegatedPropertyDelegateDescriptorImpl -import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor -import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl +import org.jetbrains.kotlin.ir.descriptors.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallableReferenceImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtProperty @@ -46,11 +44,10 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener propertyDescriptor: PropertyDescriptor, irDelegateInitializer: IrExpressionBody ): IrProperty { - val delegateDescriptor = createPropertyDelegateDescriptor(ktDelegate, propertyDescriptor) + val kPropertyType = getKPropertyTypeForDelegatedProperty(propertyDescriptor) - val irDelegate = IrFieldImpl( - ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE, - delegateDescriptor, irDelegateInitializer) + val irDelegate = generateDelegateFieldForProperty(propertyDescriptor, kPropertyType, irDelegateInitializer, ktDelegate) + val delegateDescriptor = irDelegate.descriptor as IrPropertyDelegateDescriptor val irProperty = IrPropertyImpl( ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED, true, @@ -63,7 +60,9 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener getterDescriptor, generateDelegatedPropertyGetterBody( ktDelegate, getterDescriptor, delegateReceiverValue, - createCallableReference(ktDelegate, delegateDescriptor.kPropertyType, propertyDescriptor))) + createCallableReference(ktDelegate, kPropertyType, propertyDescriptor) + ) + ) if (propertyDescriptor.isVar) { val setterDescriptor = propertyDescriptor.setter!! @@ -72,12 +71,54 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener setterDescriptor, generateDelegatedPropertySetterBody( ktDelegate, setterDescriptor, delegateReceiverValue, - createCallableReference(ktDelegate, delegateDescriptor.kPropertyType, propertyDescriptor))) + createCallableReference(ktDelegate, kPropertyType, propertyDescriptor) + ) + ) } return irProperty } + private fun getKPropertyTypeForDelegatedProperty(propertyDescriptor: PropertyDescriptor): KotlinType { + val propertyReceiverType = propertyDescriptor.extensionReceiverParameter?.type ?: + propertyDescriptor.dispatchReceiverParameter?.type + return context.reflectionTypes.getKPropertyType(Annotations.EMPTY, propertyReceiverType, propertyDescriptor.type, propertyDescriptor.isVar) + } + + private fun generateDelegateFieldForProperty( + propertyDescriptor: PropertyDescriptor, + kPropertyType: KotlinType, + irDelegateInitializer: IrExpressionBody, + ktDelegate: KtPropertyDelegate + ): IrFieldImpl { + val irActualDelegateInitializer = generateInitializerBodyForPropertyDelegate(propertyDescriptor, kPropertyType, irDelegateInitializer, ktDelegate) + + val delegateType = irActualDelegateInitializer.expression.type + val delegateDescriptor = createPropertyDelegateDescriptor(propertyDescriptor, delegateType, kPropertyType) + + return IrFieldImpl( + ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE, + delegateDescriptor, irActualDelegateInitializer + ) + } + + private fun generateInitializerBodyForPropertyDelegate( + property: VariableDescriptorWithAccessors, + kPropertyType: KotlinType, + irDelegateInitializer: IrExpressionBody, + ktDelegate: KtPropertyDelegate + ): IrExpressionBody { + val provideDelegateResolvedCall = get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, property) + ?: return irDelegateInitializer + + val statementGenerator = BodyGenerator(property, context).createStatementGenerator() + val provideDelegateCall = statementGenerator.pregenerateCall(provideDelegateResolvedCall) + provideDelegateCall.setExplicitReceiverValue(OnceExpressionValue(irDelegateInitializer.expression)) + provideDelegateCall.irValueArgumentsByIndex[1] = createCallableReference(ktDelegate, kPropertyType, property) + val irProvideDelegate = CallGenerator(statementGenerator).generateCall(ktDelegate.startOffset, ktDelegate.endOffset, provideDelegateCall) + return IrExpressionBodyImpl(irProvideDelegate) + } + private fun createBackingFieldValueForDelegate(delegateDescriptor: IrPropertyDelegateDescriptor, ktDelegate: KtPropertyDelegate): IntermediateValue { val thisClass = delegateDescriptor.correspondingProperty.containingDeclaration as? ClassDescriptor val thisValue = thisClass?.let { @@ -96,11 +137,22 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener variableDescriptor: VariableDescriptorWithAccessors, irDelegateInitializer: IrExpression ): IrLocalDelegatedProperty { - val delegateDescriptor = createLocalPropertyDelegatedDescriptor(ktDelegate, variableDescriptor) + val kPropertyType = getKPropertyTypeForLocalDelegatedProperty(variableDescriptor) + + val irActualDelegateInitializer = + generateInitializerBodyForPropertyDelegate( + variableDescriptor, kPropertyType, + IrExpressionBodyImpl(irDelegateInitializer), ktDelegate + ).expression + val delegateType = irActualDelegateInitializer.type + + val delegateDescriptor = createLocalPropertyDelegatedDescriptor(variableDescriptor, delegateType, kPropertyType) val irDelegate = IrVariableImpl( ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE, - delegateDescriptor, irDelegateInitializer) + delegateDescriptor, + irActualDelegateInitializer + ) val irLocalDelegatedProperty = IrLocalDelegatedPropertyImpl( ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED, @@ -135,27 +187,22 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener getterDescriptor, body) private fun createLocalPropertyDelegatedDescriptor( - ktDelegate: KtPropertyDelegate, - variableDescriptor: VariableDescriptorWithAccessors + variableDescriptor: VariableDescriptorWithAccessors, + delegateType: KotlinType, + kPropertyType: KotlinType ): IrLocalDelegatedPropertyDelegateDescriptor { - val delegateType = getInferredTypeWithImplicitCastsOrFail(ktDelegate.expression!!) - val kPropertyType = context.reflectionTypes.getKPropertyType( - Annotations.EMPTY, null, variableDescriptor.type, variableDescriptor.isVar) return IrLocalDelegatedPropertyDelegateDescriptorImpl(variableDescriptor, delegateType, kPropertyType) } + private fun getKPropertyTypeForLocalDelegatedProperty(variableDescriptor: VariableDescriptorWithAccessors) = + context.reflectionTypes.getKPropertyType(Annotations.EMPTY, null, variableDescriptor.type, variableDescriptor.isVar) + private fun createPropertyDelegateDescriptor( - ktDelegate: KtPropertyDelegate, - propertyDescriptor: PropertyDescriptor - ): IrPropertyDelegateDescriptor { - val delegateType = getInferredTypeWithImplicitCastsOrFail(ktDelegate.expression!!) - val propertyReceiverType = propertyDescriptor.extensionReceiverParameter?.type ?: - propertyDescriptor.dispatchReceiverParameter?.type - val kPropertyType = context.reflectionTypes.getKPropertyType( - Annotations.EMPTY, propertyReceiverType, propertyDescriptor.type, propertyDescriptor.isVar) - val delegateDescriptor = IrPropertyDelegateDescriptorImpl(propertyDescriptor, delegateType, kPropertyType) - return delegateDescriptor - } + propertyDescriptor: PropertyDescriptor, + delegateType: KotlinType, + kPropertyType: KotlinType + ): IrPropertyDelegateDescriptor = + IrPropertyDelegateDescriptorImpl(propertyDescriptor, delegateType, kPropertyType) fun generateDelegatedPropertyGetterBody( ktDelegate: KtPropertyDelegate, diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.kt b/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.kt new file mode 100644 index 00000000000..6f806de654d --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.kt @@ -0,0 +1,13 @@ +// WITH_RUNTIME + +class MyClass(val value: String) + +operator fun MyClass.provideDelegate(host: Any?, p: Any): String = + this.value + +operator fun String.getValue(receiver: Any?, p: Any): String = + this + +val testO by MyClass("O") +val testK by "K" +val testOK = testO + testK diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.txt b/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.txt new file mode 100644 index 00000000000..235ce96de69 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.txt @@ -0,0 +1,60 @@ +FILE /differentReceivers.kt + CLASS CLASS MyClass + CONSTRUCTOR public constructor MyClass(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='MyClass' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=MyClass origin=null + FUN public operator fun MyClass.provideDelegate(host: kotlin.Any?, p: kotlin.Any): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any) on MyClass: String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=MyClass origin=null + FUN public operator fun kotlin.String.getValue(receiver: kotlin.Any?, p: kotlin.Any): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(Any?, Any) on String: String' + GET_VAR '' type=kotlin.String origin=null + PROPERTY public val testO: kotlin.String + FIELD DELEGATE val `testO$delegate`: kotlin.String + EXPRESSION_BODY + CALL 'provideDelegate(Any?, Any) on MyClass: String' type=kotlin.String origin=null + $receiver: CALL 'constructor MyClass(String)' type=MyClass origin=null + value: CONST String type=kotlin.String value='O' + host: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testO: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR public fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any) on String: String' type=kotlin.String origin=null + $receiver: GET_FIELD '`testO$delegate`: String' type=kotlin.String origin=null + receiver: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testO: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + PROPERTY public val testK: kotlin.String + FIELD DELEGATE val `testK$delegate`: kotlin.String + EXPRESSION_BODY + CONST String type=kotlin.String value='K' + FUN DELEGATED_PROPERTY_ACCESSOR public fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any) on String: String' type=kotlin.String origin=null + $receiver: GET_FIELD '`testK$delegate`: String' type=kotlin.String origin=null + receiver: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testK: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + PROPERTY public val testOK: kotlin.String + FIELD PROPERTY_BACKING_FIELD public val testOK: kotlin.String + EXPRESSION_BODY + CALL 'plus(Any?): String' type=kotlin.String origin=PLUS + $this: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + other: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + FUN DEFAULT_PROPERTY_ACCESSOR public fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'testOK: String' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/local.kt b/compiler/testData/ir/irText/declarations/provideDelegate/local.kt new file mode 100644 index 00000000000..e0a5ec7abc8 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/local.kt @@ -0,0 +1,12 @@ +class Delegate(val value: String) { + operator fun getValue(thisRef: Any?, property: Any?) = value +} + +class DelegateProvider(val value: String) { + operator fun provideDelegate(thisRef: Any?, property: Any?) = Delegate(value) +} + +fun foo() { + val testMember by DelegateProvider("OK") +} + diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/local.txt b/compiler/testData/ir/irText/declarations/provideDelegate/local.txt new file mode 100644 index 00000000000..8e9a639f109 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/local.txt @@ -0,0 +1,56 @@ +FILE /local.kt + CLASS CLASS Delegate + CONSTRUCTOR public constructor Delegate(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Delegate' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=Delegate origin=null + FUN public final operator fun getValue(thisRef: kotlin.Any?, property: kotlin.Any?): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(Any?, Any?): String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=Delegate origin=null + CLASS CLASS DelegateProvider + CONSTRUCTOR public constructor DelegateProvider(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='DelegateProvider' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=DelegateProvider origin=null + FUN public final operator fun provideDelegate(thisRef: kotlin.Any?, property: kotlin.Any?): Delegate + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any?): Delegate' + CALL 'constructor Delegate(String)' type=Delegate origin=null + value: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=DelegateProvider origin=null + FUN public fun foo(): kotlin.Unit + BLOCK_BODY + LOCAL_DELEGATED_PROPERTY val testMember: kotlin.String + VAR DELEGATE val `testMember$delegate`: Delegate + CALL 'provideDelegate(Any?, Any?): Delegate' type=Delegate origin=null + $this: CALL 'constructor DelegateProvider(String)' type=DelegateProvider origin=null + value: CONST String type=kotlin.String value='OK' + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE 'testMember: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR local final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any?): String' type=kotlin.String origin=null + $this: GET_VAR '`testMember$delegate`: Delegate' type=Delegate origin=null + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE 'testMember: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.kt b/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.kt new file mode 100644 index 00000000000..aac495b6526 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.kt @@ -0,0 +1,18 @@ +// WITH_RUNTIME + +class MyClass(val value: String) + +operator fun MyClass.provideDelegate(host: Any?, p: Any): String = + this.value + +operator fun String.getValue(receiver: Any?, p: Any): String = + this + + +fun box(): String { + val testO by MyClass("O") + val testK by "K" + val testOK = testO + testK + + return testOK +} diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.txt b/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.txt new file mode 100644 index 00000000000..f866f2f0a64 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.txt @@ -0,0 +1,56 @@ +FILE /localDifferentReceivers.kt + CLASS CLASS MyClass + CONSTRUCTOR public constructor MyClass(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='MyClass' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=MyClass origin=null + FUN public operator fun MyClass.provideDelegate(host: kotlin.Any?, p: kotlin.Any): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any) on MyClass: String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=MyClass origin=null + FUN public operator fun kotlin.String.getValue(receiver: kotlin.Any?, p: kotlin.Any): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(Any?, Any) on String: String' + GET_VAR '' type=kotlin.String origin=null + FUN public fun box(): kotlin.String + BLOCK_BODY + LOCAL_DELEGATED_PROPERTY val testO: kotlin.String + VAR DELEGATE val `testO$delegate`: kotlin.String + CALL 'provideDelegate(Any?, Any) on MyClass: String' type=kotlin.String origin=null + $receiver: CALL 'constructor MyClass(String)' type=MyClass origin=null + value: CONST String type=kotlin.String value='O' + host: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testO: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR local final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any) on String: String' type=kotlin.String origin=null + $receiver: GET_VAR '`testO$delegate`: String' type=kotlin.String origin=null + receiver: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testO: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + LOCAL_DELEGATED_PROPERTY val testK: kotlin.String + VAR DELEGATE val `testK$delegate`: kotlin.String + CONST String type=kotlin.String value='K' + FUN DELEGATED_PROPERTY_ACCESSOR local final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any) on String: String' type=kotlin.String origin=null + $receiver: GET_VAR '`testK$delegate`: String' type=kotlin.String origin=null + receiver: CONST Null type=kotlin.Nothing? value='null' + p: CALLABLE_REFERENCE 'testK: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + VAR val testOK: kotlin.String + CALL 'plus(Any?): String' type=kotlin.String origin=PLUS + $this: CALL '(): String' type=kotlin.String origin=GET_LOCAL_PROPERTY + other: CALL '(): String' type=kotlin.String origin=GET_LOCAL_PROPERTY + RETURN type=kotlin.Nothing from='box(): String' + GET_VAR 'testOK: String' type=kotlin.String origin=null diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/member.kt b/compiler/testData/ir/irText/declarations/provideDelegate/member.kt new file mode 100644 index 00000000000..5a0ffbf7e81 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/member.kt @@ -0,0 +1,12 @@ +class Delegate(val value: String) { + operator fun getValue(thisRef: Any?, property: Any?) = value +} + +class DelegateProvider(val value: String) { + operator fun provideDelegate(thisRef: Any?, property: Any?) = Delegate(value) +} + +class Host { + val testMember by DelegateProvider("OK") +} + diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/member.txt b/compiler/testData/ir/irText/declarations/provideDelegate/member.txt new file mode 100644 index 00000000000..3828f1233d7 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/member.txt @@ -0,0 +1,61 @@ +FILE /member.kt + CLASS CLASS Delegate + CONSTRUCTOR public constructor Delegate(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Delegate' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=Delegate origin=null + FUN public final operator fun getValue(thisRef: kotlin.Any?, property: kotlin.Any?): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(Any?, Any?): String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=Delegate origin=null + CLASS CLASS DelegateProvider + CONSTRUCTOR public constructor DelegateProvider(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='DelegateProvider' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=DelegateProvider origin=null + FUN public final operator fun provideDelegate(thisRef: kotlin.Any?, property: kotlin.Any?): Delegate + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any?): Delegate' + CALL 'constructor Delegate(String)' type=Delegate origin=null + value: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=DelegateProvider origin=null + CLASS CLASS Host + CONSTRUCTOR public constructor Host() + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Host' + PROPERTY public final val testMember: kotlin.String + FIELD DELEGATE val `testMember$delegate`: Delegate + EXPRESSION_BODY + CALL 'provideDelegate(Any?, Any?): Delegate' type=Delegate origin=null + $this: CALL 'constructor DelegateProvider(String)' type=DelegateProvider origin=null + value: CONST String type=kotlin.String value='OK' + thisRef: GET_VAR '' type=Host origin=null + property: CALLABLE_REFERENCE 'testMember: String' type=kotlin.reflect.KProperty1 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any?): String' type=kotlin.String origin=null + $this: GET_FIELD '`testMember$delegate`: Delegate' type=Delegate origin=null + receiver: GET_VAR '' type=Host origin=null + thisRef: GET_VAR '' type=Host origin=null + property: CALLABLE_REFERENCE 'testMember: String' type=kotlin.reflect.KProperty1 origin=PROPERTY_REFERENCE_FOR_DELEGATE diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.kt b/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.kt new file mode 100644 index 00000000000..bf538dbb143 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.kt @@ -0,0 +1,12 @@ +object Host { + class StringDelegate(val s: String) { + operator fun getValue(receiver: String, p: Any) = receiver + s + } + + operator fun String.provideDelegate(host: Any?, p: Any) = StringDelegate(this) + + val String.plusK by "K" + + val ok = "O".plusK +} + diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.txt b/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.txt new file mode 100644 index 00000000000..77ff6298acb --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.txt @@ -0,0 +1,59 @@ +FILE /memberExtension.kt + CLASS OBJECT Host + CONSTRUCTOR private constructor Host() + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Host' + CLASS CLASS StringDelegate + CONSTRUCTOR public constructor StringDelegate(s: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='StringDelegate' + PROPERTY public final val s: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val s: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter s: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 's: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=Host.StringDelegate origin=null + FUN public final operator fun getValue(receiver: kotlin.String, p: kotlin.Any): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(String, Any): String' + CALL 'plus(Any?): String' type=kotlin.String origin=PLUS + $this: GET_VAR 'value-parameter receiver: String' type=kotlin.String origin=null + other: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=Host.StringDelegate origin=null + FUN public final operator fun kotlin.String.provideDelegate(host: kotlin.Any?, p: kotlin.Any): Host.StringDelegate + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any) on String: Host.StringDelegate' + CALL 'constructor StringDelegate(String)' type=Host.StringDelegate origin=null + s: GET_VAR '' type=kotlin.String origin=null + PROPERTY public final val kotlin.String.plusK: kotlin.String + FIELD DELEGATE val `plusK$delegate`: Host.StringDelegate + EXPRESSION_BODY + CALL 'provideDelegate(Any?, Any) on String: Host.StringDelegate' type=Host.StringDelegate origin=null + $this: GET_VAR '' type=Host origin=null + $receiver: CONST String type=kotlin.String value='K' + host: GET_VAR '' type=Host origin=null + p: CALLABLE_REFERENCE 'plusK: String on String' type=kotlin.reflect.KProperty1 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR public final fun kotlin.String.(): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='() on String: String' + CALL 'getValue(String, Any): String' type=kotlin.String origin=null + $this: GET_FIELD '`plusK$delegate`: Host.StringDelegate' type=Host.StringDelegate origin=null + receiver: GET_VAR '' type=Host origin=null + receiver: GET_VAR '' type=kotlin.String origin=null + p: CALLABLE_REFERENCE 'plusK: String on String' type=kotlin.reflect.KProperty1 origin=PROPERTY_REFERENCE_FOR_DELEGATE + PROPERTY public final val ok: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val ok: kotlin.String + EXPRESSION_BODY + CALL '() on String: String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=Host origin=null + $receiver: CONST String type=kotlin.String value='O' + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'ok: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=Host origin=null diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.kt b/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.kt new file mode 100644 index 00000000000..f1b00f83412 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.kt @@ -0,0 +1,10 @@ +class Delegate(val value: String) { + operator fun getValue(thisRef: Any?, property: Any?) = value +} + +class DelegateProvider(val value: String) { + operator fun provideDelegate(thisRef: Any?, property: Any?) = Delegate(value) +} + +val testTopLevel by DelegateProvider("OK") + diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.txt b/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.txt new file mode 100644 index 00000000000..028b55e077b --- /dev/null +++ b/compiler/testData/ir/irText/declarations/provideDelegate/topLevel.txt @@ -0,0 +1,55 @@ +FILE /topLevel.kt + CLASS CLASS Delegate + CONSTRUCTOR public constructor Delegate(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Delegate' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=Delegate origin=null + FUN public final operator fun getValue(thisRef: kotlin.Any?, property: kotlin.Any?): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='getValue(Any?, Any?): String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=Delegate origin=null + CLASS CLASS DelegateProvider + CONSTRUCTOR public constructor DelegateProvider(value: kotlin.String) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='DelegateProvider' + PROPERTY public final val value: kotlin.String + FIELD PROPERTY_BACKING_FIELD public final val value: kotlin.String + EXPRESSION_BODY + GET_VAR 'value-parameter value: String' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=DelegateProvider origin=null + FUN public final operator fun provideDelegate(thisRef: kotlin.Any?, property: kotlin.Any?): Delegate + BLOCK_BODY + RETURN type=kotlin.Nothing from='provideDelegate(Any?, Any?): Delegate' + CALL 'constructor Delegate(String)' type=Delegate origin=null + value: CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_VAR '' type=DelegateProvider origin=null + PROPERTY public val testTopLevel: kotlin.String + FIELD DELEGATE val `testTopLevel$delegate`: Delegate + EXPRESSION_BODY + CALL 'provideDelegate(Any?, Any?): Delegate' type=Delegate origin=null + $this: CALL 'constructor DelegateProvider(String)' type=DelegateProvider origin=null + value: CONST String type=kotlin.String value='OK' + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE 'testTopLevel: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE + FUN DELEGATED_PROPERTY_ACCESSOR public fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL 'getValue(Any?, Any?): String' type=kotlin.String origin=null + $this: GET_FIELD '`testTopLevel$delegate`: Delegate' type=Delegate origin=null + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE 'testTopLevel: String' type=kotlin.reflect.KProperty0 origin=PROPERTY_REFERENCE_FOR_DELEGATE diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index d5842f1dad9..3b8cd1a7e5e 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -268,6 +268,51 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/typeAlias.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/ir/irText/declarations/provideDelegate") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ProvideDelegate extends AbstractIrTextTestCase { + public void testAllFilesPresentInProvideDelegate() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/declarations/provideDelegate"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("differentReceivers.kt") + public void testDifferentReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/differentReceivers.kt"); + doTest(fileName); + } + + @TestMetadata("local.kt") + public void testLocal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/local.kt"); + doTest(fileName); + } + + @TestMetadata("localDifferentReceivers.kt") + public void testLocalDifferentReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/localDifferentReceivers.kt"); + doTest(fileName); + } + + @TestMetadata("member.kt") + public void testMember() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/member.kt"); + doTest(fileName); + } + + @TestMetadata("memberExtension.kt") + public void testMemberExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/memberExtension.kt"); + doTest(fileName); + } + + @TestMetadata("topLevel.kt") + public void testTopLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/provideDelegate/topLevel.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/ir/irText/errors")