Properties without accessors are generated as

IrGetBackingField / IrSetBackingField expressions.
This commit is contained in:
Dmitry Petrov
2016-09-05 15:06:38 +03:00
committed by Dmitry Petrov
parent a1ad828ea8
commit ceeccfa1b7
40 changed files with 359 additions and 122 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.ir.expressions.IrThisReferenceImpl
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -108,8 +109,14 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
val descriptor = resolvedCall.candidateDescriptor
return when (descriptor) {
is SyntheticFieldDescriptor ->
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor.propertyDescriptor, operator)
is SyntheticFieldDescriptor -> {
val receiverValue = resolvedCall.dispatchReceiver?.let {
statementGenerator.generateReceiver(ktLeft, it)
}
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor.propertyDescriptor,
receiverValue, operator)
}
is LocalVariableDescriptor ->
if (descriptor.isDelegated)
DelegatedLocalPropertyLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, operator)
@@ -131,7 +138,10 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
resolvedCall: ResolvedCall<*>
): AssignmentReceiver {
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
return BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, null)
val thisClass = getThisClass()
val irThis = IrThisReferenceImpl(ktLeft.startOffset, ktLeft.endOffset, thisClass.defaultType, thisClass)
return BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor,
RematerializableValue(irThis), null)
}
val propertyReceiver = statementGenerator.generateCallReceiver(
@@ -148,6 +158,15 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
statementGenerator.scopeOwner.let { it is ConstructorDescriptor || it is ClassDescriptor } &&
resolvedCall.dispatchReceiver is ThisClassReceiver
private fun getThisClass(): ClassDescriptor {
val scopeOwner = statementGenerator.scopeOwner
return when (scopeOwner) {
is ConstructorDescriptor -> scopeOwner.containingDeclaration
is ClassDescriptor -> scopeOwner
else -> scopeOwner.containingDeclaration as ClassDescriptor
}
}
private fun generateArrayAccessAssignmentReceiver(ktLeft: KtArrayAccessExpression, irOperator: IrOperator): ArrayAccessAssignmentReceiver {
val irArray = statementGenerator.generateExpression(ktLeft.arrayExpression!!)
val irIndexExpressions = ktLeft.indexExpressions.map { statementGenerator.generateExpression(it) }
@@ -288,7 +288,7 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
val valueParameterDescriptor = getOrFail(BindingContext.VALUE_PARAMETER, ktParameter)
irBlockBody.addStatement(
createPropertyInitializationExpression(
initializePropertyInPrimaryConstructor(
ktParameter, propertyDescriptor,
IrGetVariableImpl(ktParameter.startOffset, ktParameter.endOffset,
valueParameterDescriptor, IrOperator.INITIALIZE_PROPERTY_FROM_PARAMETER)
@@ -298,7 +298,15 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
}
}
private fun createPropertyInitializationExpression(ktElement: KtElement, propertyDescriptor: PropertyDescriptor, value: IrExpression) =
IrSetBackingFieldImpl(ktElement.startOffset, ktElement.endOffset, propertyDescriptor, value)
private fun initializePropertyInPrimaryConstructor(
ktElement: KtElement,
propertyDescriptor: PropertyDescriptor,
value: IrExpression
): IrExpression {
val thisClass = propertyDescriptor.containingDeclaration as ClassDescriptor
return IrSetBackingFieldImpl(ktElement.startOffset, ktElement.endOffset, propertyDescriptor,
IrThisReferenceImpl(ktElement.startOffset, ktElement.endOffset, thisClass.defaultType, thisClass),
value)
}
}
@@ -85,13 +85,15 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
call: CallBuilder
): IrExpression {
return call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val getter = descriptor.getter ?:
context.syntheticDescriptorsFactory.getOrCreatePropertyGetter(descriptor)
IrGetterCallImpl(startOffset, endOffset, getter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
IrOperator.GET_PROPERTY,
call.superQualifier)
descriptor.getter?.let { getter ->
IrGetterCallImpl(startOffset, endOffset, getter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
IrOperator.GET_PROPERTY,
call.superQualifier)
} ?: IrGetBackingFieldImpl(startOffset, endOffset, descriptor,
dispatchReceiverValue?.load(),
IrOperator.GET_PROPERTY, call.superQualifier)
}
}
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableAccessorDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrLocalDelegatedPropertyDelegateDescriptor
@@ -35,10 +32,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.builders.irBlockBody
import org.jetbrains.kotlin.psi2ir.builders.irGet
import org.jetbrains.kotlin.psi2ir.builders.irReturn
import org.jetbrains.kotlin.psi2ir.intermediate.BackingFieldLValue
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
import org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
import org.jetbrains.kotlin.psi2ir.intermediate.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinType
@@ -82,8 +76,13 @@ class DelegatedPropertyGenerator(override val context: GeneratorContext) : Gener
return irProperty
}
private fun createBackingFieldValueForDelegate(delegateDescriptor: IrPropertyDelegateDescriptor, ktDelegate: KtPropertyDelegate) =
BackingFieldLValue(ktDelegate.startOffset, ktDelegate.endOffset, delegateDescriptor, null)
private fun createBackingFieldValueForDelegate(delegateDescriptor: IrPropertyDelegateDescriptor, ktDelegate: KtPropertyDelegate): IntermediateValue {
val thisClass = delegateDescriptor.correspondingProperty.containingDeclaration as? ClassDescriptor
val thisValue = thisClass?.let {
RematerializableValue(IrThisReferenceImpl(ktDelegate.startOffset, ktDelegate.endOffset, thisClass.defaultType, thisClass))
}
return BackingFieldLValue(ktDelegate.startOffset, ktDelegate.endOffset, delegateDescriptor, thisValue, null)
}
private fun createCallableReference(ktElement: KtElement, type: KotlinType, referencedDescriptor: CallableDescriptor): IrCallableReference =
IrCallableReferenceImpl(ktElement.startOffset, ktElement.endOffset, type,
@@ -24,15 +24,16 @@ class BackingFieldLValue(
val startOffset: Int,
val endOffset: Int,
val descriptor: PropertyDescriptor,
val receiver: IntermediateValue?,
val operator: IrOperator?
) : LValue, AssignmentReceiver {
override val type: KotlinType get() = descriptor.type
override fun store(irExpression: IrExpression): IrExpression =
IrSetBackingFieldImpl(startOffset, endOffset, descriptor, irExpression, operator)
IrSetBackingFieldImpl(startOffset, endOffset, descriptor, receiver?.load(), irExpression, operator)
override fun load(): IrExpression =
IrGetBackingFieldImpl(startOffset, endOffset, descriptor, operator)
IrGetBackingFieldImpl(startOffset, endOffset, descriptor, receiver?.load(), operator)
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this)
@@ -37,23 +37,27 @@ class SimplePropertyLValue(
override fun load(): IrExpression =
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val getter = descriptor.getter ?: context.syntheticDescriptorsFactory.getOrCreatePropertyGetter(descriptor)
IrGetterCallImpl(startOffset, endOffset, getter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
irOperator,
superQualifier)
descriptor.getter?.let { getter ->
IrGetterCallImpl(startOffset, endOffset, getter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
irOperator,
superQualifier)
} ?: IrGetBackingFieldImpl(startOffset, endOffset, descriptor,
dispatchReceiverValue?.load(), irOperator, superQualifier)
}
override fun store(irExpression: IrExpression) =
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val setter = descriptor.setter ?: context.syntheticDescriptorsFactory.getOrCreatePropertySetter(descriptor)
IrSetterCallImpl(startOffset, endOffset, setter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
irExpression,
irOperator,
superQualifier)
descriptor.setter?.let { setter ->
IrSetterCallImpl(startOffset, endOffset, setter,
dispatchReceiverValue?.load(),
extensionReceiverValue?.load(),
irExpression,
irOperator,
superQualifier)
} ?: IrSetBackingFieldImpl(startOffset, endOffset, descriptor,
dispatchReceiverValue?.load(), irExpression, irOperator, superQualifier)
}
override fun assign(withLValue: (LValue) -> IrExpression) =
@@ -55,7 +55,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitorVoid {
}
override fun visitBlock(expression: IrBlock) {
expression.acceptChildren(this, null)
expression.acceptChildrenVoid(this)
val type = expression.type
if (KotlinBuiltIns.isUnit(type)) return
if (expression.statements.isEmpty()) return
@@ -67,25 +67,31 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitorVoid {
}
override fun visitReturn(expression: IrReturn) {
expression.acceptChildren(this, null)
expression.acceptChildrenVoid(this)
expression.value?.replaceWithCast(expression.returnTarget.returnType)
}
override fun visitSetVariable(expression: IrSetVariable) {
expression.acceptChildren(this, null)
expression.acceptChildrenVoid(this)
expression.value.replaceWithCast(expression.descriptor.type)
}
override fun visitSetBackingField(expression: IrSetBackingField) {
expression.acceptChildrenVoid(this)
expression.value.replaceWithCast(expression.descriptor.type)
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildren(this, null)
declaration.acceptChildrenVoid(this)
declaration.initializer?.replaceWithCast(declaration.descriptor.type)
}
override fun visitWhen(expression: IrWhen) {
expression.acceptChildren(this, null)
expression.acceptChildrenVoid(this)
for (branchIndex in expression.branchIndices) {
expression.getNthCondition(branchIndex)!!.replaceWithCast(builtIns.booleanType)
@@ -95,19 +101,19 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitorVoid {
}
override fun visitLoop(loop: IrLoop) {
loop.acceptChildren(this, null)
loop.acceptChildrenVoid(this)
loop.condition.replaceWithCast(builtIns.booleanType)
}
override fun visitThrow(expression: IrThrow) {
expression.acceptChildren(this, null)
expression.acceptChildrenVoid(this)
expression.value.replaceWithCast(builtIns.throwable.defaultType)
}
override fun visitTryCatch(tryCatch: IrTryCatch) {
tryCatch.acceptChildren(this, null)
tryCatch.acceptChildrenVoid(this)
val resultType = tryCatch.type
@@ -119,6 +125,7 @@ class InsertImplicitCasts(val builtIns: KotlinBuiltIns): IrElementVisitorVoid {
override fun visitVararg(expression: IrVararg) {
expression.acceptChildrenVoid(this)
for (element in expression.elements) {
when (element) {
is IrSpreadElement -> element.expression.replaceWithCast(expression.type)
@@ -74,7 +74,7 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
companion object {
private val EXPECTED_OCCURRENCES_PATTERN = Regex("""^\s*//\s*(\d+)\s*(.*)$""")
private val IR_TREES_TXT_PATTERN = Regex("""// \s*<<<\s+(.*)$""")
private val IR_FILE_TXT_PATTERN = Regex("""// IR_FILE: (.*)$""")
private val IGNORE_ERRORS_PATTERN = Regex("""// !IGNORE_ERRORS""")
internal fun shouldIgnoreErrors(wholeFile: File): Boolean =
@@ -84,14 +84,14 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
val regexps = ArrayList<RegexpInText>()
val treeFiles = ArrayList<IrTreeFileLabel>()
for ((lineNumber, line) in testFile.content.split("\n").withIndex()) {
for (line in testFile.content.split("\n")) {
EXPECTED_OCCURRENCES_PATTERN.matchEntire(line)?.let { matchResult ->
regexps.add(RegexpInText(matchResult.groupValues[1], matchResult.groupValues[2].trim()))
}
?: IR_TREES_TXT_PATTERN.find(line)?.let { matchResult ->
?: IR_FILE_TXT_PATTERN.find(line)?.let { matchResult ->
val fileName = matchResult.groupValues[1].trim()
val file = createExpectedTextFile(testFile, dir, fileName)
treeFiles.add(IrTreeFileLabel(file, lineNumber))
treeFiles.add(IrTreeFileLabel(file, 0))
}
}
@@ -22,6 +22,7 @@ const val ARGUMENT0_SLOT = 0
const val ARGUMENT1_SLOT = 1
const val DISPATCH_RECEIVER_SLOT = -1
const val EXTENSION_RECEIVER_SLOT = -2
const val BACKING_FIELD_RECEIVER_SLOT = -1
const val FUNCTION_BODY_SLOT = -1
const val ANONYMOUS_INITIALIZER_BODY_SLOT = -1
const val MODULE_SLOT = 0
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -24,6 +25,8 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
interface IrBackingFieldExpression : IrDeclarationReference {
override val descriptor: PropertyDescriptor
val superQualifier: ClassDescriptor?
var receiver: IrExpression?
val operator: IrOperator?
}
@@ -38,20 +41,54 @@ abstract class IrBackingFieldExpressionBase(
endOffset: Int,
descriptor: PropertyDescriptor,
type: KotlinType,
override val operator: IrOperator? = null
) : IrDeclarationReferenceBase<PropertyDescriptor>(startOffset, endOffset, type, descriptor), IrBackingFieldExpression
override val operator: IrOperator? = null,
override val superQualifier: ClassDescriptor? = null
) : IrDeclarationReferenceBase<PropertyDescriptor>(startOffset, endOffset, type, descriptor), IrBackingFieldExpression {
override final var receiver: IrExpression? = null
set(value) {
value?.assertDetached()
field?.detach()
field = value
value?.setTreeLocation(this, BACKING_FIELD_RECEIVER_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
BACKING_FIELD_RECEIVER_SLOT -> receiver
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
BACKING_FIELD_RECEIVER_SLOT -> receiver = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
}
class IrGetBackingFieldImpl(
startOffset: Int,
endOffset: Int,
descriptor: PropertyDescriptor,
operator: IrOperator? = null
) : IrBackingFieldExpressionBase(startOffset, endOffset, descriptor, descriptor.type, operator), IrGetBackingField {
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
) : IrBackingFieldExpressionBase(startOffset, endOffset, descriptor, descriptor.type, operator, superQualifier), IrGetBackingField {
constructor(
startOffset: Int,
endOffset: Int,
descriptor: PropertyDescriptor,
receiver: IrExpression?,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
) : this(startOffset, endOffset, descriptor, operator, superQualifier) {
this.receiver = receiver
}
override fun getChild(slot: Int): IrElement? =
null
super.getChild(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
throwNoSuchSlot(slot)
super.replaceChild(slot, newChild)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
@@ -59,7 +96,7 @@ class IrGetBackingFieldImpl(
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
// no children
receiver?.accept(visitor, data)
}
}
@@ -67,15 +104,19 @@ class IrSetBackingFieldImpl(
startOffset: Int,
endOffset: Int,
descriptor: PropertyDescriptor,
operator: IrOperator? = null
) : IrBackingFieldExpressionBase(startOffset, endOffset, descriptor, descriptor.type.builtIns.unitType, operator), IrSetBackingField {
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
) : IrBackingFieldExpressionBase(startOffset, endOffset, descriptor, descriptor.type.builtIns.unitType, operator, superQualifier), IrSetBackingField {
constructor(
startOffset: Int,
endOffset: Int,
descriptor: PropertyDescriptor,
receiver: IrExpression?,
value: IrExpression,
operator: IrOperator? = null
) : this(startOffset, endOffset, descriptor, operator) {
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
) : this(startOffset, endOffset, descriptor, operator, superQualifier) {
this.receiver = receiver
this.value = value
}
@@ -92,12 +133,13 @@ class IrSetBackingFieldImpl(
override fun getChild(slot: Int): IrElement? =
when (slot) {
CHILD_EXPRESSION_SLOT -> value
else -> null
else -> super.getChild(slot)
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
CHILD_EXPRESSION_SLOT -> value = newChild.assertCast()
else -> super.replaceChild(slot, newChild)
}
}
@@ -106,6 +148,7 @@ class IrSetBackingFieldImpl(
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
receiver?.accept(visitor, data)
value.accept(visitor, data)
}
}
@@ -94,6 +94,19 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
}
}
override fun visitGetBackingField(expression: IrGetBackingField, data: String) {
expression.dumpLabeledElementWith(data) {
expression.receiver?.accept(this, "receiver")
}
}
override fun visitSetBackingField(expression: IrSetBackingField, data: String) {
expression.dumpLabeledElementWith(data) {
expression.receiver?.accept(this, "receiver")
expression.value.accept(this, "value")
}
}
override fun visitWhen(expression: IrWhen, data: String) {
expression.dumpLabeledElementWith(data) {
for (i in 0 .. expression.branchesCount - 1) {
@@ -62,8 +62,9 @@ interface IrElementVisitor<out R, in D> {
fun visitGetEnumValue(expression: IrGetEnumValue, data: D) = visitSingletonReference(expression, data)
fun visitGetVariable(expression: IrGetVariable, data: D) = visitDeclarationReference(expression, data)
fun visitSetVariable(expression: IrSetVariable, data: D) = visitDeclarationReference(expression, data)
fun visitGetBackingField(expression: IrGetBackingField, data: D) = visitDeclarationReference(expression, data)
fun visitSetBackingField(expression: IrSetBackingField, data: D) = visitDeclarationReference(expression, data)
fun visitBackingFieldReference(expression: IrBackingFieldExpression, data: D) = visitDeclarationReference(expression, data)
fun visitGetBackingField(expression: IrGetBackingField, data: D) = visitBackingFieldReference(expression, data)
fun visitSetBackingField(expression: IrSetBackingField, data: D) = visitBackingFieldReference(expression, data)
fun visitGetExtensionReceiver(expression: IrGetExtensionReceiver, data: D) = visitDeclarationReference(expression, data)
fun visitGeneralCall(expression: IrGeneralCall, data: D) = visitDeclarationReference(expression, data)
fun visitCall(expression: IrCall, data: D) = visitGeneralCall(expression, data)
@@ -129,10 +129,13 @@ interface IrElementVisitorVoid : IrElementVisitor<Unit, Nothing?> {
fun visitSetVariable(expression: IrSetVariable) = visitDeclarationReference(expression)
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?) = visitSetVariable(expression)
fun visitGetBackingField(expression: IrGetBackingField) = visitDeclarationReference(expression)
fun visitBackingFieldReference(expression: IrBackingFieldExpression) = visitDeclarationReference(expression)
override fun visitBackingFieldReference(expression: IrBackingFieldExpression, data: Nothing?) = visitBackingFieldReference(expression)
fun visitGetBackingField(expression: IrGetBackingField) = visitBackingFieldReference(expression)
override fun visitGetBackingField(expression: IrGetBackingField, data: Nothing?) = visitGetBackingField(expression)
fun visitSetBackingField(expression: IrSetBackingField) = visitDeclarationReference(expression)
fun visitSetBackingField(expression: IrSetBackingField) = visitBackingFieldReference(expression)
override fun visitSetBackingField(expression: IrSetBackingField, data: Nothing?) = visitSetBackingField(expression)
fun visitGetExtensionReceiver(expression: IrGetExtensionReceiver) = visitDeclarationReference(expression)