Delegated properties.

This commit is contained in:
Dmitry Petrov
2016-09-01 12:52:49 +03:00
committed by Dmitry Petrov
parent 865d2c43c7
commit 759f0168c2
19 changed files with 415 additions and 58 deletions
@@ -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)