From 838b639692e5345584e1f4ccfd9ebe048b35523a Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 9 Sep 2016 12:15:37 +0300 Subject: [PATCH] IrComposite - block introducing immediate declarations to the surrounding scope. E.g., destructuring declaration is represented as IrComposite. --- .../psi2ir/generators/StatementGenerator.kt | 8 +-- .../intermediate/RematerializableValue.kt | 3 +- .../kotlin/ir/expressions/IrBlock.kt | 18 +++--- .../jetbrains/kotlin/ir/expressions/IrBody.kt | 4 +- .../kotlin/ir/expressions/impl/IrBlockImpl.kt | 37 ++----------- .../ir/expressions/impl/IrCompositeImpl.kt | 39 +++++++++++++ .../impl/IrContainerExpressionBase.kt | 55 +++++++++++++++++++ .../kotlin/ir/util/RenderIrElement.kt | 3 + .../kotlin/ir/visitors/IrElementVisitor.kt | 4 +- .../ir/visitors/IrElementVisitorVoid.kt | 8 ++- .../ir/irText/expressions/destructuring1.txt | 2 +- .../smartCastsWithDestructuring.txt | 2 +- 12 files changed, 132 insertions(+), 51 deletions(-) create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCompositeImpl.kt create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrContainerExpressionBase.kt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 0fe4cbddeeb..78536ba6971 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -93,10 +93,8 @@ class StatementGenerator( ) override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Nothing?): IrStatement { - // TODO use some special form that introduces multiple declarations into surrounding scope? - - val irBlock = IrBlockImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, - context.builtIns.unitType, IrOperator.DESTRUCTURING_DECLARATION) + val irBlock = IrCompositeImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, + context.builtIns.unitType, IrOperator.DESTRUCTURING_DECLARATION) val ktInitializer = multiDeclaration.initializer!! val containerValue = scope.createTemporaryVariableInBlock(ktInitializer.genExpr(), irBlock, "container") @@ -105,7 +103,7 @@ class StatementGenerator( return irBlock } - fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: IntermediateValue) { + fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrContainerExpressionBase, containerValue: IntermediateValue) { val callGenerator = CallGenerator(this) for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/RematerializableValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/RematerializableValue.kt index f2559a526c4..3dd9fd3f869 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/RematerializableValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/RematerializableValue.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy +import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase import org.jetbrains.kotlin.psi2ir.generators.Scope import org.jetbrains.kotlin.types.KotlinType @@ -28,7 +29,7 @@ class RematerializableValue(val irExpression: IrExpressionWithCopy) : Intermedia override fun load(): IrExpression = irExpression.copy() } -fun Scope.createTemporaryVariableInBlock(irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): IntermediateValue { +fun Scope.createTemporaryVariableInBlock(irExpression: IrExpression, block: IrContainerExpressionBase, nameHint: String? = null): IntermediateValue { val temporaryVariable = createTemporaryVariable(irExpression, nameHint) block.addStatement(temporaryVariable) return VariableLValue(temporaryVariable) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt index 327f4fd105d..132044d9417 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt @@ -16,13 +16,17 @@ package org.jetbrains.kotlin.ir.expressions -import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.detach - - -interface IrBlock : IrExpression { +interface IrContainerExpression : IrExpression, IrStatementContainer { val operator: IrOperator? - - val statements: List + val isTransparentScope: Boolean } +interface IrBlock : IrContainerExpression { + override val isTransparentScope: Boolean + get() = false +} + +interface IrComposite : IrContainerExpression { + override val isTransparentScope: Boolean + get() = true +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBody.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBody.kt index 67782216cf7..42de05e1bb2 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBody.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBody.kt @@ -25,10 +25,12 @@ interface IrExpressionBody : IrBody { var expression: IrExpression } -interface IrBlockBody : IrBody { +interface IrStatementContainer { val statements: List } +interface IrBlockBody : IrBody, IrStatementContainer + interface IrSyntheticBody : IrBody { val kind: IrSyntheticBodyKind } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt index 4d7fedea6a9..d2411a51a91 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt @@ -16,49 +16,20 @@ package org.jetbrains.kotlin.ir.expressions.impl -import org.jetbrains.kotlin.ir.* +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.detach import org.jetbrains.kotlin.ir.expressions.IrBlock import org.jetbrains.kotlin.ir.expressions.IrOperator import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.types.KotlinType -import java.util.* -class IrBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType, override val operator: IrOperator? = null): - IrExpressionBase(startOffset, endOffset, type), IrBlock { +class IrBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType, operator: IrOperator? = null): + IrContainerExpressionBase(startOffset, endOffset, type, operator), IrBlock { constructor(startOffset: Int, endOffset: Int, type: KotlinType, operator: IrOperator?, statements: List) : this(startOffset, endOffset, type, operator) { addAll(statements) } - override val statements: MutableList = ArrayList(2) - - fun addStatement(statement: IrStatement) { - statement.assertDetached() - statement.setTreeLocation(this, statements.size) - statements.add(statement) - } - - fun addAll(newStatements: List) { - newStatements.forEach { it.assertDetached() } - val originalSize = this.statements.size - this.statements.addAll(newStatements) - newStatements.forEachIndexed { i, irStatement -> - irStatement.setTreeLocation(this, originalSize + i) - } - } - - override fun getChild(slot: Int): IrElement? = - statements.getOrNull(slot) - - override fun replaceChild(slot: Int, newChild: IrElement) { - if (slot < 0 || slot >= statements.size) throwNoSuchSlot(slot) - - newChild.assertDetached() - statements[slot].detach() - statements[slot] = newChild.assertCast() - newChild.setTreeLocation(this, slot) - } - override fun accept(visitor: IrElementVisitor, data: D): R = visitor.visitBlock(this, data) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCompositeImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCompositeImpl.kt new file mode 100644 index 00000000000..08ef7a49419 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrCompositeImpl.kt @@ -0,0 +1,39 @@ +/* + * 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.expressions.impl + +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.expressions.IrComposite +import org.jetbrains.kotlin.ir.expressions.IrOperator +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.types.KotlinType + + +class IrCompositeImpl(startOffset: Int, endOffset: Int, type: KotlinType, operator: IrOperator? = null) : + IrContainerExpressionBase(startOffset, endOffset, type, operator), IrComposite { + constructor(startOffset: Int, endOffset: Int, type: KotlinType, operator: IrOperator?, statements: List) : + this(startOffset, endOffset, type, operator) { + addAll(statements) + } + + override fun accept(visitor: IrElementVisitor, data: D): R = + visitor.visitComposite(this, data) + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + statements.forEach { it.accept(visitor, data) } + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrContainerExpressionBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrContainerExpressionBase.kt new file mode 100644 index 00000000000..2191e669196 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrContainerExpressionBase.kt @@ -0,0 +1,55 @@ +/* + * 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.expressions.impl + +import org.jetbrains.kotlin.ir.* +import org.jetbrains.kotlin.ir.expressions.IrOperator +import org.jetbrains.kotlin.ir.expressions.IrContainerExpression +import org.jetbrains.kotlin.types.KotlinType +import java.util.* + +abstract class IrContainerExpressionBase(startOffset: Int, endOffset: Int, type: KotlinType, override val operator: IrOperator? = null): + IrExpressionBase(startOffset, endOffset, type), IrContainerExpression { + override val statements: MutableList = ArrayList(2) + + fun addStatement(statement: IrStatement) { + statement.assertDetached() + statement.setTreeLocation(this, statements.size) + statements.add(statement) + } + + fun addAll(newStatements: List) { + newStatements.forEach { it.assertDetached() } + val originalSize = this.statements.size + this.statements.addAll(newStatements) + newStatements.forEachIndexed { i, irStatement -> + irStatement.setTreeLocation(this, originalSize + i) + } + } + + override fun getChild(slot: Int): IrElement? = + statements.getOrNull(slot) + + override fun replaceChild(slot: Int, newChild: IrElement) { + if (slot < 0 || slot >= statements.size) throwNoSuchSlot(slot) + + newChild.assertDetached() + statements[slot].detach() + statements[slot] = newChild.assertCast() + newChild.setTreeLocation(this, slot) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt index 2efed2d5878..ad1858628ff 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt @@ -102,6 +102,9 @@ class RenderIrElementVisitor : IrElementVisitor { override fun visitBlock(expression: IrBlock, data: Nothing?): String = "BLOCK type=${expression.type.render()} operator=${expression.operator}" + override fun visitComposite(expression: IrComposite, data: Nothing?): String = + "COMPOSITE type=${expression.type.render()} operator=${expression.operator}" + override fun visitReturn(expression: IrReturn, data: Nothing?): String = "RETURN type=${expression.type.render()} from='${expression.returnTarget.ref()}'" diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt index 11a5d1a0671..f7b8961e618 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitor.kt @@ -52,7 +52,9 @@ interface IrElementVisitor { fun visitVararg(expression: IrVararg, data: D) = visitExpression(expression, data) fun visitSpreadElement(spread: IrSpreadElement, data: D) = visitElement(spread, data) - fun visitBlock(expression: IrBlock, data: D) = visitExpression(expression, data) + fun visitContainerExpression(expression: IrContainerExpression, data: D) = visitExpression(expression, data) + fun visitBlock(expression: IrBlock, data: D) = visitContainerExpression(expression, data) + fun visitComposite(expression: IrComposite, data: D) = visitContainerExpression(expression, data) fun visitStringConcatenation(expression: IrStringConcatenation, data: D) = visitExpression(expression, data) fun visitThisReference(expression: IrThisReference, data: D) = visitExpression(expression, data) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitorVoid.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitorVoid.kt index 133e4cbf3f8..bd1e7857356 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitorVoid.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/visitors/IrElementVisitorVoid.kt @@ -102,7 +102,13 @@ interface IrElementVisitorVoid : IrElementVisitor { fun visitSpreadElement(spread: IrSpreadElement) = visitElement(spread) override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?) = visitSpreadElement(spread) - fun visitBlock(expression: IrBlock) = visitExpression(expression) + fun visitContainerExpression(expression: IrContainerExpression) = visitExpression(expression) + override fun visitContainerExpression(expression: IrContainerExpression, data: Nothing?) = visitContainerExpression(expression) + + fun visitComposite(expression: IrComposite) = visitContainerExpression(expression) + override fun visitComposite(expression: IrComposite, data: Nothing?) = visitComposite(expression) + + fun visitBlock(expression: IrBlock) = visitContainerExpression(expression) override fun visitBlock(expression: IrBlock, data: Nothing?) = visitBlock(expression) fun visitStringConcatenation(expression: IrStringConcatenation) = visitExpression(expression) diff --git a/compiler/testData/ir/irText/expressions/destructuring1.txt b/compiler/testData/ir/irText/expressions/destructuring1.txt index 23f445d6b42..d2c64f536c2 100644 --- a/compiler/testData/ir/irText/expressions/destructuring1.txt +++ b/compiler/testData/ir/irText/expressions/destructuring1.txt @@ -19,7 +19,7 @@ FILE /destructuring1.kt CONST Int type=kotlin.Int value='2' FUN public fun B.test(): kotlin.Unit BLOCK_BODY - BLOCK type=kotlin.Unit operator=DESTRUCTURING_DECLARATION + COMPOSITE type=kotlin.Unit operator=DESTRUCTURING_DECLARATION VAR val tmp0_container: A GET_OBJECT 'A' type=A VAR val x: kotlin.Int diff --git a/compiler/testData/ir/irText/expressions/smartCastsWithDestructuring.txt b/compiler/testData/ir/irText/expressions/smartCastsWithDestructuring.txt index f2d8912b955..baaafb386a7 100644 --- a/compiler/testData/ir/irText/expressions/smartCastsWithDestructuring.txt +++ b/compiler/testData/ir/irText/expressions/smartCastsWithDestructuring.txt @@ -15,7 +15,7 @@ FILE /smartCastsWithDestructuring.kt if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=I2 GET_VAR 'value-parameter x: I1' type=I1 operator=null then: RETURN type=kotlin.Nothing from='test(I1): Unit' - BLOCK type=kotlin.Unit operator=DESTRUCTURING_DECLARATION + COMPOSITE type=kotlin.Unit operator=DESTRUCTURING_DECLARATION VAR val tmp0_container: I1 GET_VAR 'value-parameter x: I1' type=I1 operator=null VAR val c1: kotlin.Int