IR: destructuring declarations in regular statements
This commit is contained in:
committed by
Dmitry Petrov
parent
37cce98d19
commit
f903fb8ad3
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user