Generate get/set for local delegated properties as accessor calls.

This commit is contained in:
Dmitry Petrov
2016-09-02 14:42:40 +03:00
committed by Dmitry Petrov
parent f2e778d2d0
commit 8b95992af1
8 changed files with 104 additions and 6 deletions
@@ -114,7 +114,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor.propertyDescriptor, operator)
is LocalVariableDescriptor ->
if (descriptor.isDelegated)
TODO("Delegated local variable")
DelegatedLocalPropertyLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, operator)
else
VariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, operator)
is PropertyDescriptor ->
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -35,7 +36,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
is VariableDescriptor ->
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
IrGetVariableImpl(startOffset, endOffset, descriptor, operator)
generateGetVariable(startOffset, endOffset, descriptor, operator)
}
is FunctionDescriptor ->
generateFunctionCall(descriptor, startOffset, endOffset, operator, call)
@@ -44,6 +45,12 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
}
}
fun generateGetVariable(startOffset: Int, endOffset: Int, descriptor: VariableDescriptor, operator: IrOperator? = null) =
if (descriptor is LocalVariableDescriptor && descriptor.isDelegated)
IrCallImpl(startOffset, endOffset, descriptor.type, descriptor.getter!!, operator ?: IrOperator.GET_LOCAL_PROPERTY)
else
IrGetVariableImpl(startOffset, endOffset, descriptor, operator)
fun generateDelegatingConstructorCall(startOffset: Int, endOffset: Int, call: CallBuilder) : IrExpression {
val descriptor = call.descriptor
if (descriptor !is ConstructorDescriptor) throw AssertionError("Constructor expected: $descriptor")
@@ -255,7 +255,7 @@ class StatementGenerator(
CallGenerator(this).generateCall(expression.startOffset, expression.endOffset, pregenerateCall(resolvedCall))
}
is VariableDescriptor ->
IrGetVariableImpl(expression.startOffset, expression.endOffset, descriptor)
CallGenerator(this).generateGetVariable(expression.startOffset, expression.endOffset, descriptor)
else ->
IrDummyExpression(
expression.startOffset, expression.endOffset, getInferredTypeWithImplicitCastsOrFail(expression),
@@ -0,0 +1,43 @@
/*
* 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.psi2ir.intermediate
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.ir.expressions.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.types.KotlinType
class DelegatedLocalPropertyLValue(
val startOffset: Int,
val endOffset: Int,
val descriptor: VariableDescriptorWithAccessors,
val irOperator: IrOperator? = null
) : LValue, AssignmentReceiver {
override val type: KotlinType get() = descriptor.type
override fun load(): IrExpression =
IrCallImpl(startOffset, endOffset, descriptor.type, descriptor.getter!!, irOperator)
override fun store(irExpression: IrExpression): IrExpression =
IrCallImpl(startOffset, endOffset, descriptor.type, descriptor.setter!!, irOperator).apply {
putArgument(0, irExpression)
}
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this)
}
@@ -72,6 +72,7 @@ interface IrOperator {
object DESTRUCTURING_DECLARATION : IrOperatorImpl("DESTRUCTURING_DECLARATION")
object GET_PROPERTY : IrOperatorImpl("GET_PROPERTY")
object GET_LOCAL_PROPERTY : IrOperatorImpl("GET_LOCAL_PROPERTY")
object IF : IrOperatorImpl("IF")
object WHEN : IrOperatorImpl("WHEN")
@@ -69,6 +69,12 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String =
"ANONYMOUS_INITIALIZER ${declaration.descriptor.name}"
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
"LOCAL_DELEGATED_PROPERTY ${declaration.descriptor.render()}"
override fun visitLocalPropertyAccessor(declaration: IrLocalPropertyAccessor, data: Nothing?): String =
"LOCAL_PROPERTY_ACCESSOR ${declaration.descriptor.name}" // can't render, see nullability for modality
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
"EXPRESSION_BODY"
@@ -1,4 +1,11 @@
fun test1() {
val x by lazy { 42 }
println(x)
}
fun test2() {
var x by hashMapOf<String, Int>()
x = 0
x++
x += 1
}
@@ -1,7 +1,7 @@
FILE /localDelegatedProperties.kt
FUN public fun test1(): kotlin.Unit
BLOCK_BODY
? IrLocalDelegatedPropertyImpl x
LOCAL_DELEGATED_PROPERTY val x: kotlin.Int
VAR val `x$delegate`: kotlin.Lazy<kotlin.Int>
CALL .lazy type=kotlin.Lazy<kotlin.Int> operator=null
initializer: BLOCK type=() -> kotlin.Int operator=LAMBDA
@@ -10,7 +10,7 @@ FILE /localDelegatedProperties.kt
RETURN type=kotlin.Nothing from=<anonymous>
CONST Int type=kotlin.Int value='42'
CALLABLE_REFERENCE local final fun <anonymous>(): kotlin.Int type=() -> kotlin.Int
? IrLocalPropertyAccessorImpl <get-x>
LOCAL_PROPERTY_ACCESSOR <get-x>
BLOCK_BODY
RETURN type=kotlin.Nothing from=<get-x>
CALL .getValue type=kotlin.Int operator=null
@@ -18,4 +18,38 @@ FILE /localDelegatedProperties.kt
thisRef: CONST Null type=kotlin.Nothing? value='null'
property: CALLABLE_REFERENCE val x: kotlin.Int type=kotlin.reflect.KProperty0<kotlin.Int>
CALL .println type=kotlin.Unit operator=null
message: GET_VAR x type=kotlin.Int operator=null
message: CALL .<get-x> type=kotlin.Int operator=GET_LOCAL_PROPERTY
FUN public fun test2(): kotlin.Unit
BLOCK_BODY
LOCAL_DELEGATED_PROPERTY var x: kotlin.Int
VAR val `x$delegate`: java.util.HashMap<kotlin.String, kotlin.Int>
CALL .hashMapOf type=java.util.HashMap<kotlin.String, kotlin.Int> operator=null
LOCAL_PROPERTY_ACCESSOR <get-x>
BLOCK_BODY
RETURN type=kotlin.Nothing from=<get-x>
CALL .getValue type=kotlin.Int operator=null
$receiver: GET_VAR x$delegate type=java.util.HashMap<kotlin.String, kotlin.Int> operator=null
thisRef: CONST Null type=kotlin.Nothing? value='null'
property: CALLABLE_REFERENCE var x: kotlin.Int type=kotlin.reflect.KMutableProperty0<kotlin.Int>
LOCAL_PROPERTY_ACCESSOR <set-x>
BLOCK_BODY
RETURN type=kotlin.Nothing from=<set-x>
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Int
CALL .setValue type=kotlin.Unit operator=null
$receiver: GET_VAR x$delegate type=java.util.HashMap<kotlin.String, kotlin.Int> operator=null
thisRef: CONST Null type=kotlin.Nothing? value='null'
property: CALLABLE_REFERENCE var x: kotlin.Int type=kotlin.reflect.KMutableProperty0<kotlin.Int>
value: GET_VAR value type=kotlin.Int operator=null
CALL .<set-x> type=kotlin.Int operator=EQ
value: CONST Int type=kotlin.Int value='0'
BLOCK type=kotlin.Int operator=POSTFIX_INCR
VAR val tmp0: kotlin.Int
CALL .<get-x> type=kotlin.Int operator=POSTFIX_INCR
CALL .<set-x> type=kotlin.Int operator=POSTFIX_INCR
value: CALL .inc type=kotlin.Int operator=POSTFIX_INCR
$this: GET_VAR tmp0 type=kotlin.Int operator=null
GET_VAR tmp0 type=kotlin.Int operator=null
CALL .<set-x> type=kotlin.Int operator=PLUSEQ
value: CALL .plus type=kotlin.Int operator=PLUSEQ
$this: CALL .<get-x> type=kotlin.Int operator=PLUSEQ
other: CONST Int type=kotlin.Int value='1'