IR: destructuring declarations in regular statements

This commit is contained in:
Dmitry Petrov
2016-08-15 13:03:35 +03:00
committed by Dmitry Petrov
parent 37cce98d19
commit f903fb8ad3
6 changed files with 142 additions and 75 deletions
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -26,30 +25,52 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize
import java.util.*
class IrCallGenerator(
override val context: IrGeneratorContext,
val irStatementGenerator: IrStatementGenerator
) : IrGenerator {
class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context
private val temporaries = newHashMapWithExpectedSize<KtExpression, VariableDescriptor>(3)
fun putTemporary(ktExpression: KtExpression, temporaryVariableDescriptor: VariableDescriptor) {
temporaries[ktExpression] = temporaryVariableDescriptor
}
private fun generateExpressionOrTemporary(ktExpression: KtExpression): IrExpression {
val temporary = temporaries[ktExpression]
return if (temporary != null)
IrGetVariableExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, getType(ktExpression), temporary)
else
irStatementGenerator.generateExpression(ktExpression)
}
fun generateCall(
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
) = generateCall(ktExpression, getTypeOrFail(ktExpression), resolvedCall, operator, superQualifier)
fun generateCall(
ktExpression: KtExpression,
resultType: KotlinType?,
resolvedCall: ResolvedCall<out CallableDescriptor>,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
): IrExpression {
val descriptor = resolvedCall.resultingDescriptor
return when (descriptor) {
is PropertyDescriptor ->
IrGetPropertyExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, getTypeOrFail(ktExpression),
ktExpression.startOffset, ktExpression.endOffset, resultType,
resolvedCall.call.isSafeCall(), descriptor
).apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
}
is FunctionDescriptor ->
generateFunctionCall(descriptor, ktExpression, operator, resolvedCall, superQualifier)
generateFunctionCall(descriptor, ktExpression, resultType, operator, resolvedCall, superQualifier)
else ->
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
}
@@ -72,11 +93,11 @@ class IrCallGenerator(
private fun generateFunctionCall(
descriptor: FunctionDescriptor,
ktExpression: KtExpression,
resultType: KotlinType?,
operator: IrOperator?,
resolvedCall: ResolvedCall<out CallableDescriptor>,
superQualifier: ClassDescriptor?
): IrExpression {
val resultType = getTypeOrFail(ktExpression)
val irCall = IrCallExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, resultType,
descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
@@ -103,8 +124,10 @@ class IrCallGenerator(
irCall: IrCallExpression,
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
resultType: KotlinType
resultType: KotlinType?
): IrExpression {
// TODO use IrLetExpression?
val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values
val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType,
@@ -142,7 +165,7 @@ class IrCallGenerator(
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver ->
irStatementGenerator.generateStatement(receiver.expression).assertCast()
generateExpressionOrTemporary(receiver.expression)
is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
@@ -160,7 +183,7 @@ class IrCallGenerator(
is DefaultValueArgument ->
return null
is ExpressionValueArgument ->
return irStatementGenerator.generateStatement(valueArgument.valueArgument!!.getArgumentExpression()!!).assertCast()
return generateExpressionOrTemporary(valueArgument.valueArgument!!.getArgumentExpression()!!)
is VarargValueArgument ->
TODO("vararg")
else ->
@@ -71,21 +71,22 @@ class IrLocalDeclarationsFactory(val scopeOwner: DeclarationDescriptor) : IrDecl
IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier("tmp${nextTemporaryIndex()}"), type)
fun createTemporaryVariable(ktElement: KtElement, type: KotlinType): IrVariable =
IrVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
IrVariableImpl(ktElement.startOffset, ktElement.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(type))
fun createTemporaryVariable(irExpression: IrExpression): IrVariable =
IrVariableImpl(irExpression.startOffset, irExpression.endOffset,
IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
IrVariableImpl(irExpression.startOffset, irExpression.endOffset, IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(
irExpression.type
?: throw AssertionError("No type for $irExpression")
)
).apply { initializer = irExpression }
irExpression.type
?: throw AssertionError("No type for $irExpression")
),
irExpression)
fun createLocalVariable(ktElement: KtElement, descriptor: VariableDescriptor): IrVariable =
IrVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.DEFINED,
IrVariableImpl(ktElement.startOffset, ktElement.endOffset, IrDeclarationOriginKind.DEFINED,
descriptor)
fun createLocalVariable(ktElement: KtElement, descriptor: VariableDescriptor, initializer: IrExpression): IrVariable =
IrVariableImpl(ktElement.startOffset, ktElement.endOffset, IrDeclarationOriginKind.DEFINED,
descriptor, initializer)
}
@@ -37,14 +37,14 @@ class IrStatementGenerator(
override val context: IrGeneratorContext,
val declarationFactory: IrLocalDeclarationsFactory
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
private val irCallGenerator = IrCallGenerator(context, this)
fun generateStatement(ktExpression: KtExpression) = ktExpression.generate()
fun generateExpression(ktExpression: KtExpression) = ktExpression.generateExpression()
private fun KtElement.generate(): IrStatement =
deparenthesize()
.accept(this@IrStatementGenerator, null)
.applySmartCastIfNeeded(this)
.accept(this@IrStatementGenerator, null)
.applySmartCastIfNeeded(this)
private fun KtElement.generateExpression(): IrExpression =
generate().assertCast()
@@ -56,7 +56,7 @@ class IrStatementGenerator(
return IrTypeOperatorExpressionImpl(
ktElement.startOffset, ktElement.endOffset, smartCastType,
IrTypeOperator.SMART_AS, this@applySmartCastIfNeeded, smartCastType
)
)
}
}
return this
@@ -76,6 +76,29 @@ class IrStatementGenerator(
return irLocalVariable
}
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement {
// TODO use some special form that introduces multiple declarations into surrounding scope?
val irBlock = IrBlockExpressionImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, getType(multiDeclaration),
hasResult = false, isDesugared = true)
val ktInitializer = multiDeclaration.initializer!!
val irInitializer = declarationFactory.createTemporaryVariable(ktInitializer.generateExpression())
irBlock.addStatement(irInitializer)
val irCallGenerator = IrCallGenerator(this).apply { putTemporary(ktInitializer, irInitializer.descriptor) }
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry)
val irComponentCall = irCallGenerator.generateCall(ktEntry, componentVariable.type, componentResolvedCall,
IrOperator.COMPONENT_N.withIndex(index + 1))
val irComponentVar = declarationFactory.createLocalVariable(ktEntry, componentVariable, irComponentCall)
irBlock.addStatement(irComponentVar)
}
return irBlock
}
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
hasResult = isUsedAsExpression(expression), isDesugared = false)
@@ -133,9 +156,9 @@ class IrStatementGenerator(
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
else
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
is PropertyDescriptor -> {
irCallGenerator.generateCall(expression, resolvedCall)
IrCallGenerator(this).generateCall(expression, resolvedCall)
}
is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
@@ -153,7 +176,7 @@ class IrStatementGenerator(
TODO("VariableAsFunctionResolvedCall = variable call + invoke call")
}
return irCallGenerator.generateCall(expression, resolvedCall)
return IrCallGenerator(this).generateCall(expression, resolvedCall)
}
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrStatement =
@@ -36,6 +36,16 @@ class IrVariableImpl(
originKind: IrDeclarationOriginKind,
override val descriptor: VariableDescriptor
) : IrDeclarationBase(startOffset, endOffset, originKind), IrVariable {
constructor(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind,
descriptor: VariableDescriptor,
initializer: IrExpression
) : this(startOffset, endOffset, originKind, descriptor) {
this.initializer = initializer
}
override var initializer: IrExpression? = null
set(value) {
value?.assertDetached()
@@ -16,54 +16,54 @@
package org.jetbrains.kotlin.ir.expressions
enum class IrOperator {
INVOKE,
PREFIX_INCR, PREFIX_DECR, POSTFIX_INCR, POSTFIX_DECR,
UMINUS,
EXCL,
EXCLEXCL,
ELVIS,
LT, GT, LTEQ, GTEQ,
EQEQ, EQEQEQ, EXCLEQ, EXCLEQEQ,
IN, NOT_IN,
ANDAND, OROR,
RANGE,
PLUS, MINUS, MUL, DIV, MOD,
EQ,
PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ,
DESTRUCTURING;
}
sealed class IrOperator {
object INVOKE : IrOperator()
object PREFIX_INCR : IrOperator()
object PREFIX_DECR : IrOperator()
object POSTFIX_INCR : IrOperator()
object POSTFIX_DECR : IrOperator()
object UMINUS : IrOperator()
object EXCL : IrOperator()
object EXCLEXCL : IrOperator()
object ELVIS : IrOperator()
object LT : IrOperator()
object GT : IrOperator()
object LTEQ : IrOperator()
object GTEQ : IrOperator()
object EQEQ : IrOperator()
object EQEQEQ : IrOperator()
object EXCLEQ : IrOperator()
object EXCLEQEQ : IrOperator()
object IN : IrOperator()
object NOT_IN : IrOperator()
object ANDAND : IrOperator()
object OROR : IrOperator()
object RANGE : IrOperator()
private val CAO_START = IrOperator.PLUSEQ.ordinal
private val CAO_END = IrOperator.MODEQ.ordinal
private val DUAL_START = IrOperator.PLUS.ordinal
private val DUAL_END = IrOperator.MOD.ordinal
private val INCR_DECR_START = IrOperator.PREFIX_INCR.ordinal
private val INCR_DECR_END = IrOperator.POSTFIX_DECR.ordinal
private val RELATIONAL_START = IrOperator.LT.ordinal
private val RELATIONAL_END = IrOperator.GTEQ.ordinal
object PLUS : IrOperator()
object MINUS : IrOperator()
object MUL : IrOperator()
object DIV : IrOperator()
object MOD : IrOperator()
fun IrOperator.isIncrementOrDecrement(): Boolean =
this.ordinal in INCR_DECR_START..INCR_DECR_END
object EQ : IrOperator()
object PLUSEQ : IrOperator()
object MINUSEQ : IrOperator()
object MULEQ : IrOperator()
object DIVEQ : IrOperator()
object MODEQ : IrOperator()
fun IrOperator.isCompoundAssignment(): Boolean =
this.ordinal in CAO_START .. CAO_END
data class COMPONENT_N private constructor(val index: Int) : IrOperator() {
companion object {
private val precreatedComponents = Array(32, ::COMPONENT_N)
fun IrOperator.isAssignmentOrCompoundAssignment(): Boolean =
this == IrOperator.EQ || isCompoundAssignment()
fun IrOperator.hasCompoundAssignmentDual(): Boolean =
this.ordinal in DUAL_START .. DUAL_END
fun IrOperator.toDualOperator(): IrOperator =
when {
isCompoundAssignment() ->
IrOperator.values()[this.ordinal - CAO_START + DUAL_START]
hasCompoundAssignmentDual() ->
IrOperator.values()[this.ordinal - DUAL_START + CAO_START]
else ->
throw UnsupportedOperationException("Operator $this is not a compound assignment")
fun withIndex(index: Int) =
if (index < precreatedComponents.size)
precreatedComponents[index]
else
COMPONENT_N(index)
}
fun IrOperator.isRelational(): Boolean =
this.ordinal in RELATIONAL_START .. RELATIONAL_END
}
}
+11 -1
View File
@@ -1,4 +1,14 @@
IrFunction public fun B.test(): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
DUMMY KtDestructuringDeclaration type=kotlin.Unit
BLOCK type=kotlin.Unit hasResult=false isDesugared=true
VAR val tmp0: A
GET_VAR A type=A
VAR val x: kotlin.Int
CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1)
$this: $RECEIVER of: test type=B
$receiver: GET_VAR tmp0 type=A
VAR val y: kotlin.Int
CALL .component2 type=kotlin.Int operator=COMPONENT_N(index=2)
$this: $RECEIVER of: test type=B
$receiver: GET_VAR tmp0 type=A