Delegated properties.
This commit is contained in:
committed by
Dmitry Petrov
parent
865d2c43c7
commit
759f0168c2
@@ -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)
|
||||
@@ -66,6 +66,11 @@ open class IrBlockBodyBuilder(
|
||||
) : IrStatementsBuilder<IrBlockBody>(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)
|
||||
).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)
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+45
-6
@@ -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) =
|
||||
|
||||
+4
-1
@@ -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)
|
||||
}
|
||||
|
||||
+4
-1
@@ -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)
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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 <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||
return visitor.visitDelegate(this, data)
|
||||
}
|
||||
|
||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
initializer?.accept(visitor, data)
|
||||
}
|
||||
}
|
||||
@@ -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 <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
delegateInitializer.accept(visitor, data)
|
||||
delegate.accept(visitor, data)
|
||||
getter?.accept(visitor, data)
|
||||
setter?.accept(visitor, data)
|
||||
}
|
||||
|
||||
@@ -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 <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R =
|
||||
visitor.visitVariableDescriptor(this, data)
|
||||
}
|
||||
|
||||
internal fun getDelegateName(name: Name): Name =
|
||||
Name.identifier(name.asString() + "\$delegate")
|
||||
@@ -34,7 +34,7 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||
"? ${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<String, Nothing?> {
|
||||
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<String, Nothing?> {
|
||||
}
|
||||
|
||||
internal fun IrDeclaration.name(): String =
|
||||
descriptor?.let { it.name.toString() } ?: "<none>"
|
||||
descriptor.let { it.name.toString() }
|
||||
|
||||
internal fun DeclarationDescriptor?.render(): String =
|
||||
this?.let { DESCRIPTOR_RENDERER.render(it) } ?: "<none>"
|
||||
internal fun DeclarationDescriptor.render(): String =
|
||||
DESCRIPTOR_RENDERER.render(this)
|
||||
|
||||
internal fun KotlinType?.render(): String =
|
||||
this?.let { DESCRIPTOR_RENDERER.renderType(it) } ?: "<no-type>"
|
||||
internal fun KotlinType.render(): String =
|
||||
DESCRIPTOR_RENDERER.renderType(this)
|
||||
}
|
||||
}
|
||||
@@ -22,34 +22,35 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
|
||||
interface IrElementVisitor<out R, in D> {
|
||||
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 <T> visitConst(expression: IrConst<T>, 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 <T> visitConst(expression: IrConst<T>, 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<out R, in D> {
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
val test1 by lazy { 42 }
|
||||
|
||||
class C(val map: MutableMap<String, Any>) {
|
||||
val test2 by lazy { 42 }
|
||||
var test3 by map
|
||||
}
|
||||
|
||||
var test4 by hashMapOf<String, Any>()
|
||||
@@ -0,0 +1,82 @@
|
||||
FILE /delegatedProperties.kt
|
||||
PROPERTY public val test1: kotlin.Int
|
||||
DELEGATE val `test1$delegate`: kotlin.Lazy<kotlin.Int>
|
||||
EXPRESSION_BODY
|
||||
CALL .lazy type=kotlin.Lazy<kotlin.Int> operator=null
|
||||
initializer: BLOCK type=() -> kotlin.Int operator=LAMBDA
|
||||
FUN local final fun <anonymous>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<anonymous>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
CALLABLE_REFERENCE local final fun <anonymous>(): kotlin.Int type=() -> kotlin.Int
|
||||
PROPERTY_GETTER public fun <get-test1>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<get-test1>
|
||||
CALL .getValue type=kotlin.Int operator=null
|
||||
$receiver: GET_VAR test1$delegate type=kotlin.Lazy<kotlin.Int> operator=null
|
||||
thisRef: CONST Null type=kotlin.Nothing? value='null'
|
||||
property: CALLABLE_REFERENCE public val test1: kotlin.Int type=kotlin.reflect.KProperty0<kotlin.Int>
|
||||
CLASS CLASS C
|
||||
CONSTRUCTOR public constructor C(/*0*/ map: kotlin.collections.MutableMap<kotlin.String, kotlin.Any>)
|
||||
BLOCK_BODY
|
||||
SET_BACKING_FIELD map type=kotlin.Unit operator=null
|
||||
GET_VAR map type=kotlin.collections.MutableMap<kotlin.String, kotlin.Any> operator=INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
PROPERTY public final val map: kotlin.collections.MutableMap<kotlin.String, kotlin.Any>
|
||||
EXPRESSION_BODY
|
||||
GET_VAR map type=kotlin.collections.MutableMap<kotlin.String, kotlin.Any> operator=INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
PROPERTY public final val test2: kotlin.Int
|
||||
DELEGATE val `test2$delegate`: kotlin.Lazy<kotlin.Int>
|
||||
EXPRESSION_BODY
|
||||
CALL .lazy type=kotlin.Lazy<kotlin.Int> operator=null
|
||||
initializer: BLOCK type=() -> kotlin.Int operator=LAMBDA
|
||||
FUN local final fun <anonymous>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<anonymous>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
CALLABLE_REFERENCE local final fun <anonymous>(): kotlin.Int type=() -> kotlin.Int
|
||||
PROPERTY_GETTER public final fun <get-test2>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<get-test2>
|
||||
CALL .getValue type=kotlin.Int operator=null
|
||||
$receiver: GET_VAR test2$delegate type=kotlin.Lazy<kotlin.Int> operator=null
|
||||
thisRef: THIS public final class C type=C
|
||||
property: CALLABLE_REFERENCE public final val test2: kotlin.Int type=kotlin.reflect.KProperty1<C, kotlin.Int>
|
||||
PROPERTY public final var test3: kotlin.Any
|
||||
DELEGATE val `test3$delegate`: kotlin.collections.MutableMap<kotlin.String, kotlin.Any>
|
||||
EXPRESSION_BODY
|
||||
CALL .<get-map> type=kotlin.collections.MutableMap<kotlin.String, kotlin.Any> operator=GET_PROPERTY
|
||||
$this: THIS public final class C type=C
|
||||
PROPERTY_GETTER public final fun <get-test3>(): kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<get-test3>
|
||||
CALL .getValue type=kotlin.Any operator=null
|
||||
$receiver: GET_VAR test3$delegate type=kotlin.collections.MutableMap<kotlin.String, kotlin.Any> operator=null
|
||||
thisRef: THIS public final class C type=C
|
||||
property: CALLABLE_REFERENCE public final var test3: kotlin.Any type=kotlin.reflect.KMutableProperty1<C, kotlin.Any>
|
||||
PROPERTY_SETTER public final fun <set-test3>(/*0*/ <set-?>: kotlin.Any): kotlin.Unit
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<set-test3>
|
||||
CALL .setValue type=kotlin.Unit operator=null
|
||||
$receiver: GET_VAR test3$delegate type=kotlin.collections.MutableMap<kotlin.String, kotlin.Any> operator=null
|
||||
thisRef: THIS public final class C type=C
|
||||
property: CALLABLE_REFERENCE public final var test3: kotlin.Any type=kotlin.reflect.KMutableProperty1<C, kotlin.Any>
|
||||
value: GET_VAR <set-?> type=kotlin.Any operator=null
|
||||
PROPERTY public var test4: kotlin.Any
|
||||
DELEGATE val `test4$delegate`: java.util.HashMap<kotlin.String, kotlin.Any>
|
||||
EXPRESSION_BODY
|
||||
CALL .hashMapOf type=java.util.HashMap<kotlin.String, kotlin.Any> operator=null
|
||||
PROPERTY_GETTER public fun <get-test4>(): kotlin.Any
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<get-test4>
|
||||
CALL .getValue type=kotlin.Any operator=null
|
||||
$receiver: GET_VAR test4$delegate type=java.util.HashMap<kotlin.String, kotlin.Any> operator=null
|
||||
thisRef: CONST Null type=kotlin.Nothing? value='null'
|
||||
property: CALLABLE_REFERENCE public var test4: kotlin.Any type=kotlin.reflect.KMutableProperty0<kotlin.Any>
|
||||
PROPERTY_SETTER public fun <set-test4>(/*0*/ <set-?>: kotlin.Any): kotlin.Unit
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=<set-test4>
|
||||
CALL .setValue type=kotlin.Unit operator=null
|
||||
$receiver: GET_VAR test4$delegate type=java.util.HashMap<kotlin.String, kotlin.Any> operator=null
|
||||
thisRef: CONST Null type=kotlin.Nothing? value='null'
|
||||
property: CALLABLE_REFERENCE public var test4: kotlin.Any type=kotlin.reflect.KMutableProperty0<kotlin.Any>
|
||||
value: GET_VAR <set-?> type=kotlin.Any operator=null
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user