diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt index 9f7220788d8..2a0a01853ef 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/ExpressionHelpers.kt @@ -76,7 +76,6 @@ fun IrBuilderWithScope.irThis() = IrThisReferenceImpl(startOffset, endOffset, classOwner.defaultType, classOwner) } - fun IrBuilderWithScope.irGet(variable: VariableDescriptor) = IrGetVariableImpl(startOffset, endOffset, variable) @@ -127,3 +126,6 @@ fun IrBuilderWithScope.irString(value: String) = fun IrBuilderWithScope.irConcat() = IrStringConcatenationImpl(startOffset, endOffset, context.builtIns.stringType) + +fun IrBuilderWithScope.irCallableReference(type: KotlinType, descriptor: CallableDescriptor) = + IrCallableReferenceImpl(startOffset, endOffset, type, descriptor) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt index 52a648ff38f..652df12bc39 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/builders/IrBuilder.kt @@ -66,6 +66,11 @@ open class IrBlockBodyBuilder( ) : IrStatementsBuilder(context, scope, startOffset, endOffset) { private val irBlockBody = IrBlockBodyImpl(startOffset, endOffset) + inline fun blockBody(body: IrBlockBodyBuilder.() -> Unit): IrBlockBody { + body() + return doBuild() + } + override fun addStatement(irStatement: IrStatement) { irBlockBody.addStatement(irStatement) } @@ -123,4 +128,10 @@ inline fun GeneratorWithScope.irBlock(ktElement: KtElement? = null, operator: Ir ktElement?.startOffset ?: UNDEFINED_OFFSET, ktElement?.endOffset ?: UNDEFINED_OFFSET, operator, resultType - ).block(body) \ No newline at end of file + ).block(body) + +inline fun GeneratorWithScope.irBlockBody(ktElement: KtElement? = null, body: IrBlockBodyBuilder.() -> Unit) : IrBlockBody = + IrBlockBodyBuilder(context, scope, + ktElement?.startOffset ?: UNDEFINED_OFFSET, + ktElement?.endOffset ?: UNDEFINED_OFFSET + ).blockBody(body) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index f2a7e47a9b9..8b381117969 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -20,11 +20,19 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.declarations.IrFunctionBase +import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi2ir.builders.irBlockBody +import org.jetbrains.kotlin.psi2ir.builders.irCallableReference +import org.jetbrains.kotlin.psi2ir.builders.irGet +import org.jetbrains.kotlin.psi2ir.builders.irReturn +import org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue +import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue import org.jetbrains.kotlin.resolve.BindingContext +import java.lang.AssertionError import java.util.* class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: GeneratorContext): GeneratorWithScope { @@ -59,7 +67,7 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: return irBlockBody } - fun generatePropertyInitializerBody(ktInitializer: KtExpression): IrBody = + fun generatePropertyInitializerBody(ktInitializer: KtExpression): IrExpressionBody = IrExpressionBodyImpl(ktInitializer.startOffset, ktInitializer.endOffset, createStatementGenerator().generateExpression(ktInitializer)) @@ -277,5 +285,34 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: private fun createPropertyInitializationExpression(ktElement: KtElement, propertyDescriptor: PropertyDescriptor, value: IrExpression) = IrSetBackingFieldImpl(ktElement.startOffset, ktElement.endOffset, propertyDescriptor, value) + + fun generateDelegatedPropertyGetter( + ktDelegate: KtPropertyDelegate, + delegateDescriptor: IrPropertyDelegateDescriptor, + getterDescriptor: PropertyGetterDescriptor + ): IrBody = + irBlockBody(ktDelegate) { + val statementGenerator = createStatementGenerator() + val conventionMethodResolvedCall = getOrFail(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor) + val conventionMethodCall = statementGenerator.pregenerateCall(conventionMethodResolvedCall) + conventionMethodCall.setExplicitReceiverValue(VariableLValue(ktDelegate.startOffset, ktDelegate.endOffset, delegateDescriptor)) + conventionMethodCall.irValueArgumentsByIndex[1] = irCallableReference(delegateDescriptor.kPropertyType, delegateDescriptor.correspondingProperty) + +irReturn(CallGenerator(statementGenerator).generateCall(ktDelegate.startOffset, ktDelegate.endOffset, conventionMethodCall)) + } + + fun generateDelegatedPropertySetter( + ktDelegate: KtPropertyDelegate, + delegateDescriptor: IrPropertyDelegateDescriptor, + setterDescriptor: PropertySetterDescriptor + ): IrBody = + irBlockBody(ktDelegate) { + val statementGenerator = createStatementGenerator() + val conventionMethodResolvedCall = getOrFail(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor) + val conventionMethodCall = statementGenerator.pregenerateCall(conventionMethodResolvedCall) + conventionMethodCall.setExplicitReceiverValue(VariableLValue(ktDelegate.startOffset, ktDelegate.endOffset, delegateDescriptor)) + conventionMethodCall.irValueArgumentsByIndex[1] = irCallableReference(delegateDescriptor.kPropertyType, delegateDescriptor.correspondingProperty) + conventionMethodCall.irValueArgumentsByIndex[2] = irGet(setterDescriptor.valueParameters[0]) + +irReturn(CallGenerator(statementGenerator).generateCall(ktDelegate.startOffset, ktDelegate.endOffset, conventionMethodCall)) + } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt index 8aa5978b274..a549200002f 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationGenerator.kt @@ -17,7 +17,9 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -90,27 +92,64 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator { fun generatePropertyDeclaration(ktProperty: KtProperty): IrProperty { val propertyDescriptor = getPropertyDescriptor(ktProperty) - if (ktProperty.hasDelegate()) TODO("handle delegated property") + val ktDelegate = ktProperty.delegate + return if (ktDelegate != null) + generateDelegatedProperty(ktProperty, ktDelegate, propertyDescriptor) + else + generateSimpleProperty(ktProperty, propertyDescriptor) + } + + private fun generateDelegatedProperty(ktProperty: KtProperty, ktDelegate: KtPropertyDelegate, propertyDescriptor: PropertyDescriptor): IrProperty { + val ktDelegateExpression = ktDelegate.expression!! + val delegateType = getInferredTypeWithImplicitCasts(ktDelegateExpression)!! + val propertyReceiverType = propertyDescriptor.extensionReceiverParameter?.type ?: + propertyDescriptor.dispatchReceiverParameter?.type + val kPropertyType = context.reflectionTypes.getKPropertyType( + Annotations.EMPTY, propertyReceiverType, propertyDescriptor.type, propertyDescriptor.isVar) + val delegateDescriptor = IrPropertyDelegateDescriptorImpl(delegateType, propertyDescriptor, kPropertyType) + val irDelegateInitializer = generateInitializerBody(delegateDescriptor, ktDelegateExpression) + val irDelegate = IrDelegateImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATE, + delegateDescriptor, irDelegateInitializer) + + val irProperty = IrDelegatedPropertyImpl(ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED, + propertyDescriptor, irDelegate) + + val getterDescriptor = propertyDescriptor.getter ?: throw AssertionError("Delegated property should have getter: $propertyDescriptor") + val getterBody = createBodyGenerator(getterDescriptor).generateDelegatedPropertyGetter(ktDelegate, delegateDescriptor, getterDescriptor) + irProperty.getter = IrPropertyGetterImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, + getterDescriptor, getterBody) + + if (propertyDescriptor.isVar) { + val setterDescriptor = propertyDescriptor.setter ?: throw AssertionError("Delegated property should have setter: $propertyDescriptor") + val setterBody = createBodyGenerator(setterDescriptor).generateDelegatedPropertySetter(ktDelegate, delegateDescriptor, setterDescriptor) + irProperty.setter = IrPropertySetterImpl(ktDelegate.startOffset, ktDelegate.endOffset, IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR, + setterDescriptor, setterBody) + } + + return irProperty + } + + private fun generateSimpleProperty(ktProperty: KtProperty, propertyDescriptor: PropertyDescriptor): IrSimplePropertyImpl { val initializer = ktProperty.initializer?.let { generateInitializerBody(propertyDescriptor, it) } val irProperty = IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED, propertyDescriptor, initializer) - ktProperty.getter?.let { ktGetter -> + irProperty.getter = ktProperty.getter?.let { ktGetter -> val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktGetter) val getterDescriptor = accessorDescriptor as? PropertyGetterDescriptor ?: TODO("not a getter?") val irGetterBody = generateFunctionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter")) val irGetter = IrPropertyGetterImpl(ktGetter.startOffset, ktGetter.endOffset, IrDeclarationOrigin.DEFINED, getterDescriptor, irGetterBody) - irProperty.getter = irGetter + irGetter } - ktProperty.setter?.let { ktSetter -> + irProperty.setter = ktProperty.setter?.let { ktSetter -> val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktSetter) val setterDescriptor = accessorDescriptor as? PropertySetterDescriptor ?: TODO("not a setter?") val irSetterBody = generateFunctionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter")) val irSetter = IrPropertySetterImpl(ktSetter.startOffset, ktSetter.endOffset, IrDeclarationOrigin.DEFINED, setterDescriptor, irSetterBody) - irProperty.setter = irSetter + irSetter } return irProperty @@ -126,7 +165,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator { private fun generateFunctionBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody = createBodyGenerator(scopeOwner).generateFunctionBody(ktBody) - private fun generateInitializerBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrBody = + private fun generateInitializerBody(scopeOwner: CallableDescriptor, ktBody: KtExpression): IrExpressionBody = createBodyGenerator(scopeOwner).generatePropertyInitializerBody(ktBody) private fun createBodyGenerator(descriptor: CallableDescriptor) = diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt index 2f2dcd806ed..1f7d89179be 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt @@ -17,20 +17,23 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.storage.StorageManager class GeneratorContext( val moduleDescriptor: ModuleDescriptor, val bindingContext: BindingContext ) { - val storageManager = LockBasedStorageManager.NO_LOCKS + val storageManager: StorageManager = LockBasedStorageManager.NO_LOCKS val sourceManager = PsiSourceManager() val syntheticDescriptorsFactory by lazy { SyntheticDescriptorsFactory(storageManager) } + val reflectionTypes = ReflectionTypes(moduleDescriptor) val builtIns: KotlinBuiltIns get() = moduleDescriptor.builtIns val irBuiltIns = IrBuiltIns(builtIns) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 4a961cf00bb..7ef7a5e17a9 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -205,7 +205,10 @@ class StatementGenerator( entry.expression!!.genExpr() override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression { - val resolvedCall = getResolvedCall(expression) ?: throw AssertionError("No resolved call for ${expression.text}") + val resolvedCall = getResolvedCall(expression) ?: + return IrDummyExpression(expression.startOffset, expression.endOffset, + context.builtIns.nothingType, + "No resolved call for ${expression.text}") if (resolvedCall is VariableAsFunctionResolvedCall) { val variableCall = pregenerateCall(resolvedCall.variableCall) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt index ac9c0f48799..f2b8f68fd4b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt @@ -31,8 +31,8 @@ class VariableLValue( val descriptor: VariableDescriptor, val irOperator: IrOperator? = null ) : LValue, AssignmentReceiver { - constructor(irVariable: IrVariable, irOperator: IrOperator? = null) : - this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator) + constructor(irVariable: IrVariable, irOperator: IrOperator? = null) : this( + irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator) override val type: KotlinType get() = descriptor.type diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt index 5d38943a468..5ac349ddf4d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt @@ -36,5 +36,6 @@ const val FINALLY_EXPRESSION_SLOT = -2 const val NESTED_INITIALIZERS_SLOT = -1 const val PROPERTY_GETTER_SLOT = -1 const val PROPERTY_SETTER_SLOT = -2 +const val DELEGATE_SLOT = -3 const val ENUM_ENTRY_CLASS_SLOT = -1 const val ENUM_ENTRY_INITIALIZER_SLOT = -2 \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt index 49c09d4ad16..52afee0b356 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclaration.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.ir.IrElementBase import org.jetbrains.kotlin.ir.IrStatement interface IrDeclaration : IrStatement { - val descriptor: DeclarationDescriptor? + val descriptor: DeclarationDescriptor val declarationKind: IrDeclarationKind val origin: IrDeclarationOrigin } @@ -35,6 +35,7 @@ enum class IrDeclarationKind { CONSTRUCTOR, PROPERTY, VARIABLE, + DELEGATE, CLASS, TYPEALIAS, ENUM_ENTRY, @@ -43,6 +44,8 @@ enum class IrDeclarationKind { enum class IrDeclarationOrigin { DEFINED, + DELEGATE, + DELEGATED_PROPERTY_ACCESSOR, CLASS_FOR_ENUM_ENTRY, ENUM_CLASS_SPECIAL_MEMBER, GENERATED_DATA_CLASS_MEMBER, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDelegate.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDelegate.kt new file mode 100644 index 00000000000..fc261ae455e --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDelegate.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.ir.declarations + +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.ir.* +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrExpressionBody +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + +interface IrDelegate : IrDeclaration { + override val descriptor: VariableDescriptor + + var initializer: IrExpressionBody + + override val declarationKind: IrDeclarationKind + get() = IrDeclarationKind.DELEGATE +} + +class IrDelegateImpl( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + override val descriptor: VariableDescriptor +) : IrDeclarationBase(startOffset, endOffset, origin), IrDelegate { + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: VariableDescriptor, + initializer: IrExpressionBody + ) : this(startOffset, endOffset, origin, descriptor) { + this.initializer = initializer + } + + private var initializerImpl: IrExpressionBody? = null + override var initializer: IrExpressionBody + get() = initializerImpl!! + set(value) { + value.assertDetached() + initializerImpl?.detach() + initializerImpl = value + value.setTreeLocation(this, INITIALIZER_SLOT) + } + + override fun getChild(slot: Int): IrElement? = + when (slot) { + INITIALIZER_SLOT -> initializer + else -> null + } + + override fun replaceChild(slot: Int, newChild: IrElement) { + when (slot) { + INITIALIZER_SLOT -> initializer = newChild.assertCast() + else -> throwNoSuchSlot(slot) + } + } + + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitDelegate(this, data) + } + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + initializer?.accept(visitor, data) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt index 5434e6bbb72..9f73c3f25a1 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrProperty.kt @@ -35,10 +35,9 @@ interface IrSimpleProperty : IrProperty { } interface IrDelegatedProperty : IrProperty { - var delegateInitializer: IrBody + var delegate: IrDelegate } -// TODO synchronization? abstract class IrPropertyBase( startOffset: Int, endOffset: Int, @@ -119,26 +118,37 @@ class IrDelegatedPropertyImpl( startOffset: Int, endOffset: Int, origin: IrDeclarationOrigin, - descriptor: PropertyDescriptor, - delegateInitializer: IrBody + descriptor: PropertyDescriptor ) : IrPropertyBase(startOffset, endOffset, origin, descriptor), IrDelegatedProperty { - override var delegateInitializer: IrBody = delegateInitializer + constructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + descriptor: PropertyDescriptor, + delegate: IrDelegate + ) : this(startOffset, endOffset, origin, descriptor) { + this.delegate = delegate + } + + private var delegateImpl: IrDelegate? = null + override var delegate: IrDelegate + get() = delegateImpl!! set(value) { value.assertDetached() - field.detach() - field = value - value.setTreeLocation(this, INITIALIZER_SLOT) + delegateImpl?.detach() + delegateImpl = value + value.setTreeLocation(this, DELEGATE_SLOT) } override fun getChild(slot: Int): IrElement? = when (slot) { - INITIALIZER_SLOT -> delegateInitializer + DELEGATE_SLOT -> delegate else -> super.getChild(slot) } override fun replaceChild(slot: Int, newChild: IrElement) { when (slot) { - INITIALIZER_SLOT -> delegateInitializer = newChild.assertCast() + DELEGATE_SLOT -> delegate = newChild.assertCast() else -> super.replaceChild(slot, newChild) } } @@ -147,7 +157,7 @@ class IrDelegatedPropertyImpl( visitor.visitDelegatedProperty(this, data) override fun acceptChildren(visitor: IrElementVisitor, data: D) { - delegateInitializer.accept(visitor, data) + delegate.accept(visitor, data) getter?.accept(visitor, data) setter?.accept(visitor, data) } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt new file mode 100644 index 00000000000..f68647a1e4d --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.ir.descriptors + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.VariableDescriptorImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.constants.ConstantValue +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor + +interface IrDelegateDescriptor : VariableDescriptor + +interface IrPropertyDelegateDescriptor : IrDelegateDescriptor { + val correspondingProperty: PropertyDescriptor + val kPropertyType: KotlinType +} + +class IrPropertyDelegateDescriptorImpl( + outType: KotlinType, + override val correspondingProperty: PropertyDescriptor, + override val kPropertyType: KotlinType +) : IrPropertyDelegateDescriptor, + VariableDescriptorImpl(correspondingProperty.containingDeclaration, + Annotations.EMPTY, + getDelegateName(correspondingProperty.name), + outType, SourceElement.NO_SOURCE + ) { + override fun getCompileTimeInitializer(): ConstantValue<*>? = null + + override fun getVisibility(): Visibility = Visibilities.PRIVATE + + override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor { + throw UnsupportedOperationException("Property delegate descriptor shouldn't be substituted: $this") + } + + override fun isVar(): Boolean = false + + override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R = + visitor.visitVariableDescriptor(this, data) +} + +internal fun getDelegateName(name: Name): Name = + Name.identifier(name.asString() + "\$delegate") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt index fb07b24ab2e..32672e31a0c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt @@ -34,7 +34,7 @@ class RenderIrElementVisitor : IrElementVisitor { "? ${element.javaClass.simpleName}" override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String = - "? ${declaration.javaClass.simpleName} ${declaration.descriptor?.name}" + "? ${declaration.javaClass.simpleName} ${declaration.descriptor.name}" override fun visitFile(declaration: IrFile, data: Nothing?): String = "FILE ${declaration.name}" @@ -63,6 +63,9 @@ class RenderIrElementVisitor : IrElementVisitor { override fun visitVariable(declaration: IrVariable, data: Nothing?): String = "VAR ${declaration.descriptor.render()}" + override fun visitDelegate(declaration: IrDelegate, data: Nothing?): String = + "DELEGATE ${declaration.descriptor.render()}" + override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String = "ENUM_ENTRY ${declaration.descriptor.render()}" @@ -187,12 +190,12 @@ class RenderIrElementVisitor : IrElementVisitor { } internal fun IrDeclaration.name(): String = - descriptor?.let { it.name.toString() } ?: "" + descriptor.let { it.name.toString() } - internal fun DeclarationDescriptor?.render(): String = - this?.let { DESCRIPTOR_RENDERER.render(it) } ?: "" + internal fun DeclarationDescriptor.render(): String = + DESCRIPTOR_RENDERER.render(this) - internal fun KotlinType?.render(): String = - this?.let { DESCRIPTOR_RENDERER.renderType(it) } ?: "" + internal fun KotlinType.render(): String = + DESCRIPTOR_RENDERER.renderType(this) } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt index f175cdd742c..f45137ba715 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt @@ -22,34 +22,35 @@ import org.jetbrains.kotlin.ir.expressions.* interface IrElementVisitor { fun visitElement(element: IrElement, data: D): R - fun visitModule(declaration: IrModule, data: D): R = visitElement(declaration, data) - fun visitFile(declaration: IrFile, data: D): R = visitElement(declaration, data) + fun visitModule(declaration: IrModule, data: D) = visitElement(declaration, data) + fun visitFile(declaration: IrFile, data: D) = visitElement(declaration, data) - fun visitDeclaration(declaration: IrDeclaration, data: D): R = visitElement(declaration, data) - fun visitClass(declaration: IrClass, data: D): R = visitDeclaration(declaration, data) - fun visitTypeAlias(declaration: IrTypeAlias, data: D): R = visitDeclaration(declaration, data) + fun visitDeclaration(declaration: IrDeclaration, data: D) = visitElement(declaration, data) + fun visitClass(declaration: IrClass, data: D) = visitDeclaration(declaration, data) + fun visitTypeAlias(declaration: IrTypeAlias, data: D) = visitDeclaration(declaration, data) fun visitGeneralFunction(declaration: IrGeneralFunction, data: D) = visitDeclaration(declaration, data) - fun visitFunction(declaration: IrFunction, data: D): R = visitGeneralFunction(declaration, data) - fun visitPropertyGetter(declaration: IrPropertyGetter, data: D): R = visitGeneralFunction(declaration, data) - fun visitPropertySetter(declaration: IrPropertySetter, data: D): R = visitGeneralFunction(declaration, data) - fun visitConstructor(declaration: IrConstructor, data: D): R = visitGeneralFunction(declaration, data) - fun visitProperty(declaration: IrProperty, data: D): R = visitDeclaration(declaration, data) - fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data) - fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data) + fun visitFunction(declaration: IrFunction, data: D) = visitGeneralFunction(declaration, data) + fun visitPropertyGetter(declaration: IrPropertyGetter, data: D) = visitGeneralFunction(declaration, data) + fun visitPropertySetter(declaration: IrPropertySetter, data: D) = visitGeneralFunction(declaration, data) + fun visitConstructor(declaration: IrConstructor, data: D) = visitGeneralFunction(declaration, data) + fun visitProperty(declaration: IrProperty, data: D) = visitDeclaration(declaration, data) + fun visitSimpleProperty(declaration: IrSimpleProperty, data: D) = visitProperty(declaration, data) + fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D) = visitProperty(declaration, data) fun visitVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data) + fun visitDelegate(declaration: IrDelegate, data: D) = visitDeclaration(declaration, data) fun visitEnumEntry(declaration: IrEnumEntry, data: D) = visitDeclaration(declaration, data) - fun visitBody(body: IrBody, data: D): R = visitElement(body, data) - fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data) + fun visitBody(body: IrBody, data: D) = visitElement(body, data) + fun visitExpressionBody(body: IrExpressionBody, data: D) = visitBody(body, data) fun visitBlockBody(body: IrBlockBody, data: D) = visitBody(body, data) fun visitSyntheticBody(body: IrSyntheticBody, data: D) = visitBody(body, data) - fun visitExpression(expression: IrExpression, data: D): R = visitElement(expression, data) - fun visitConst(expression: IrConst, data: D): R = visitExpression(expression, data) - fun visitVararg(expression: IrVararg, data: D): R = visitExpression(expression, data) - fun visitSpreadElement(spread: IrSpreadElement, data: D): R = visitElement(spread, data) + fun visitExpression(expression: IrExpression, data: D) = visitElement(expression, data) + fun visitConst(expression: IrConst, data: D) = visitExpression(expression, data) + fun visitVararg(expression: IrVararg, data: D) = visitExpression(expression, data) + fun visitSpreadElement(spread: IrSpreadElement, data: D) = visitElement(spread, data) - fun visitBlock(expression: IrBlock, data: D): R = visitExpression(expression, data) + fun visitBlock(expression: IrBlock, data: D) = visitExpression(expression, data) fun visitStringConcatenation(expression: IrStringConcatenation, data: D) = visitExpression(expression, data) fun visitThisReference(expression: IrThisReference, data: D) = visitExpression(expression, data) @@ -84,8 +85,8 @@ interface IrElementVisitor { fun visitBreak(jump: IrBreak, data: D) = visitBreakContinue(jump, data) fun visitContinue(jump: IrContinue, data: D) = visitBreakContinue(jump, data) - fun visitReturn(expression: IrReturn, data: D): R = visitExpression(expression, data) - fun visitThrow(expression: IrThrow, data: D): R = visitExpression(expression, data) + fun visitReturn(expression: IrReturn, data: D) = visitExpression(expression, data) + fun visitThrow(expression: IrThrow, data: D) = visitExpression(expression, data) // NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data) diff --git a/compiler/testData/ir/irText/defaultArguments.kt b/compiler/testData/ir/irText/declarations/defaultArguments.kt similarity index 100% rename from compiler/testData/ir/irText/defaultArguments.kt rename to compiler/testData/ir/irText/declarations/defaultArguments.kt diff --git a/compiler/testData/ir/irText/defaultArguments.txt b/compiler/testData/ir/irText/declarations/defaultArguments.txt similarity index 100% rename from compiler/testData/ir/irText/defaultArguments.txt rename to compiler/testData/ir/irText/declarations/defaultArguments.txt diff --git a/compiler/testData/ir/irText/declarations/delegatedProperties.kt b/compiler/testData/ir/irText/declarations/delegatedProperties.kt new file mode 100644 index 00000000000..add3eef2c0b --- /dev/null +++ b/compiler/testData/ir/irText/declarations/delegatedProperties.kt @@ -0,0 +1,8 @@ +val test1 by lazy { 42 } + +class C(val map: MutableMap) { + val test2 by lazy { 42 } + var test3 by map +} + +var test4 by hashMapOf() \ No newline at end of file diff --git a/compiler/testData/ir/irText/declarations/delegatedProperties.txt b/compiler/testData/ir/irText/declarations/delegatedProperties.txt new file mode 100644 index 00000000000..a36eaa12872 --- /dev/null +++ b/compiler/testData/ir/irText/declarations/delegatedProperties.txt @@ -0,0 +1,82 @@ +FILE /delegatedProperties.kt + PROPERTY public val test1: kotlin.Int + DELEGATE val `test1$delegate`: kotlin.Lazy + EXPRESSION_BODY + CALL .lazy type=kotlin.Lazy operator=null + initializer: BLOCK type=() -> kotlin.Int operator=LAMBDA + FUN local final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CONST Int type=kotlin.Int value='42' + CALLABLE_REFERENCE local final fun (): kotlin.Int type=() -> kotlin.Int + PROPERTY_GETTER public fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .getValue type=kotlin.Int operator=null + $receiver: GET_VAR test1$delegate type=kotlin.Lazy operator=null + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE public val test1: kotlin.Int type=kotlin.reflect.KProperty0 + CLASS CLASS C + CONSTRUCTOR public constructor C(/*0*/ map: kotlin.collections.MutableMap) + BLOCK_BODY + SET_BACKING_FIELD map type=kotlin.Unit operator=null + GET_VAR map type=kotlin.collections.MutableMap operator=INITIALIZE_PROPERTY_FROM_PARAMETER + PROPERTY public final val map: kotlin.collections.MutableMap + EXPRESSION_BODY + GET_VAR map type=kotlin.collections.MutableMap operator=INITIALIZE_PROPERTY_FROM_PARAMETER + PROPERTY public final val test2: kotlin.Int + DELEGATE val `test2$delegate`: kotlin.Lazy + EXPRESSION_BODY + CALL .lazy type=kotlin.Lazy operator=null + initializer: BLOCK type=() -> kotlin.Int operator=LAMBDA + FUN local final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CONST Int type=kotlin.Int value='42' + CALLABLE_REFERENCE local final fun (): kotlin.Int type=() -> kotlin.Int + PROPERTY_GETTER public final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .getValue type=kotlin.Int operator=null + $receiver: GET_VAR test2$delegate type=kotlin.Lazy operator=null + thisRef: THIS public final class C type=C + property: CALLABLE_REFERENCE public final val test2: kotlin.Int type=kotlin.reflect.KProperty1 + PROPERTY public final var test3: kotlin.Any + DELEGATE val `test3$delegate`: kotlin.collections.MutableMap + EXPRESSION_BODY + CALL . type=kotlin.collections.MutableMap operator=GET_PROPERTY + $this: THIS public final class C type=C + PROPERTY_GETTER public final fun (): kotlin.Any + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .getValue type=kotlin.Any operator=null + $receiver: GET_VAR test3$delegate type=kotlin.collections.MutableMap operator=null + thisRef: THIS public final class C type=C + property: CALLABLE_REFERENCE public final var test3: kotlin.Any type=kotlin.reflect.KMutableProperty1 + PROPERTY_SETTER public final fun (/*0*/ : kotlin.Any): kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .setValue type=kotlin.Unit operator=null + $receiver: GET_VAR test3$delegate type=kotlin.collections.MutableMap operator=null + thisRef: THIS public final class C type=C + property: CALLABLE_REFERENCE public final var test3: kotlin.Any type=kotlin.reflect.KMutableProperty1 + value: GET_VAR type=kotlin.Any operator=null + PROPERTY public var test4: kotlin.Any + DELEGATE val `test4$delegate`: java.util.HashMap + EXPRESSION_BODY + CALL .hashMapOf type=java.util.HashMap operator=null + PROPERTY_GETTER public fun (): kotlin.Any + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .getValue type=kotlin.Any operator=null + $receiver: GET_VAR test4$delegate type=java.util.HashMap operator=null + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE public var test4: kotlin.Any type=kotlin.reflect.KMutableProperty0 + PROPERTY_SETTER public fun (/*0*/ : kotlin.Any): kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from= + CALL .setValue type=kotlin.Unit operator=null + $receiver: GET_VAR test4$delegate type=java.util.HashMap operator=null + thisRef: CONST Null type=kotlin.Nothing? value='null' + property: CALLABLE_REFERENCE public var test4: kotlin.Any type=kotlin.reflect.KMutableProperty0 + value: GET_VAR type=kotlin.Any operator=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 5abfccac2a0..180c4dc670a 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -35,12 +35,6 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText"), Pattern.compile("^(.+)\\.kt$"), true); } - @TestMetadata("defaultArguments.kt") - public void testDefaultArguments() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/defaultArguments.kt"); - doTest(fileName); - } - @TestMetadata("compiler/testData/ir/irText/classes") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -152,6 +146,27 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { } } + @TestMetadata("compiler/testData/ir/irText/declarations") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Declarations extends AbstractIrTextTestCase { + public void testAllFilesPresentInDeclarations() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irText/declarations"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("defaultArguments.kt") + public void testDefaultArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/defaultArguments.kt"); + doTest(fileName); + } + + @TestMetadata("delegatedProperties.kt") + public void testDelegatedProperties() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/delegatedProperties.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/ir/irText/expressions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)