diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt index 5ce30c997f3..2936544d2eb 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGeneration.kt @@ -29,6 +29,10 @@ fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, recei receiver?.let { generateReceiver(ktDefaultElement, receiver) } fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue { + if (receiver is TransientReceiver) { + return TransientReceiverValue(ktDefaultElement.text, receiver.type) + } + val receiverExpression = when (receiver) { is ImplicitClassReceiver -> IrThisReferenceImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset, receiver.type, receiver.classDescriptor) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt index a47bbf73bd1..63164b47c73 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt @@ -16,44 +16,49 @@ package org.jetbrains.kotlin.psi2ir.generators +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginKind +import org.jetbrains.kotlin.ir.declarations.IrVariableImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue +import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue +import org.jetbrains.kotlin.resolve.BindingContext class LoopExpressionGenerator(val statementGenerator: StatementGenerator) : GeneratorWithScope { override val scope: Scope get() = statementGenerator.scope override val context: GeneratorContext get() = statementGenerator.context - fun generateWhileExpression(expression: KtWhileExpression): IrExpression = - generateConditionalLoop(expression, IrWhileLoopImpl(expression.startOffset, expression.endOffset, IrOperator.WHILE_LOOP)) + fun generateWhileLoop(ktWhile: KtWhileExpression): IrExpression = + generateConditionalLoop(ktWhile, IrWhileLoopImpl(ktWhile.startOffset, ktWhile.endOffset, IrOperator.WHILE_LOOP)) - fun generateDoWhileExpression(expression: KtDoWhileExpression): IrExpression = - generateConditionalLoop(expression, IrDoWhileLoopImpl(expression.startOffset, expression.endOffset, IrOperator.DO_WHILE_LOOP)) + fun generateDoWhileLoop(ktDoWhile: KtDoWhileExpression): IrExpression = + generateConditionalLoop(ktDoWhile, IrDoWhileLoopImpl(ktDoWhile.startOffset, ktDoWhile.endOffset, IrOperator.DO_WHILE_LOOP)) - private fun generateConditionalLoop(expression: KtWhileExpressionBase, irLoop: IrLoop): IrLoop { - statementGenerator.expressionBodyGenerator.putLoop(expression, irLoop) - irLoop.condition = statementGenerator.generateExpression(expression.condition!!) - irLoop.body = statementGenerator.generateExpression(expression.body!!) + private fun generateConditionalLoop(ktLoop: KtWhileExpressionBase, irLoop: IrLoop): IrLoop { + statementGenerator.expressionBodyGenerator.putLoop(ktLoop, irLoop) + irLoop.condition = statementGenerator.generateExpression(ktLoop.condition!!) + irLoop.body = statementGenerator.generateExpression(ktLoop.body!!) return irLoop } - fun generateBreakExpression(expression: KtBreakExpression): IrExpression { - val parentLoop = findParentLoop(expression) - return IrBreakImpl(expression.startOffset, expression.endOffset, context.builtIns.nothingType, parentLoop) + fun generateBreak(ktBreak: KtBreakExpression): IrExpression { + val parentLoop = findParentLoop(ktBreak) + return IrBreakImpl(ktBreak.startOffset, ktBreak.endOffset, context.builtIns.nothingType, parentLoop) } - fun generateContinueExpression(expression: KtContinueExpression): IrExpression { - val parentLoop = findParentLoop(expression) - return IrContinueImpl(expression.startOffset, expression.endOffset, context.builtIns.nothingType, parentLoop) + fun generateContinue(ktContinue: KtContinueExpression): IrExpression { + val parentLoop = findParentLoop(ktContinue) + return IrContinueImpl(ktContinue.startOffset, ktContinue.endOffset, context.builtIns.nothingType, parentLoop) } - private fun findParentLoop(expression: KtExpressionWithLabel): IrLoop = - findParentLoop(expression, expression.getTargetLabel()?.getReferencedName()) + private fun findParentLoop(ktWithLabel: KtExpressionWithLabel): IrLoop = + findParentLoop(ktWithLabel, ktWithLabel.getTargetLabel()?.getReferencedName()) - private fun findParentLoop(expression: KtExpression, targetLabel: String?): IrLoop { - var finger: KtExpression? = expression + private fun findParentLoop(ktExpression: KtExpression, targetLabel: String?): IrLoop { + var finger: KtExpression? = ktExpression while (finger != null) { finger = finger.getParentOfType(true) if (finger == null) { @@ -75,10 +80,65 @@ class LoopExpressionGenerator(val statementGenerator: StatementGenerator) : Gene throw AssertionError("No parent loop for break/continue @$targetLabel") } - private fun getLoop(finger: KtLoopExpression): IrLoop { - return statementGenerator.expressionBodyGenerator.getLoop(finger) ?: - throw AssertionError("Loop was not visited:\n${finger.text}") + private fun getLoop(ktLoop: KtLoopExpression): IrLoop { + return statementGenerator.expressionBodyGenerator.getLoop(ktLoop) ?: + throw AssertionError("Loop was not visited:\n${ktLoop.text}") } + fun generateForLoop(ktFor: KtForExpression): IrExpression { + val ktLoopParameter = ktFor.loopParameter + val ktLoopDestructuringParameter = ktFor.destructuringParameter + if (ktLoopParameter == null && ktLoopDestructuringParameter == null) { + throw AssertionError("Either loopParameter or destructuringParameter should be present:\n${ktFor.text}") + } + val ktLoopRange = ktFor.loopRange!! + val ktForBody = ktFor.body!! + val iteratorResolvedCall = getOrFail(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, ktLoopRange) + val hasNextResolvedCall = getOrFail(BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, ktLoopRange) + val nextResolvedCall = getOrFail(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, ktLoopRange) + + val callGenerator = CallGenerator(statementGenerator) + + val irForBlock = IrBlockImpl(ktFor.startOffset, ktFor.endOffset, context.builtIns.unitType, false, IrOperator.FOR_LOOP) + + val iteratorCall = statementGenerator.pregenerateCall(iteratorResolvedCall) + val irIteratorCall = callGenerator.generateCall(ktLoopRange, iteratorCall, IrOperator.FOR_LOOP_ITERATOR) + val irIterator = scope.createTemporaryVariable(irIteratorCall, "iterator") + val iteratorValue = VariableLValue(irIterator) + irForBlock.addStatement(irIterator) + + val irInnerWhile = IrWhileLoopImpl(ktFor.startOffset, ktFor.endOffset, IrOperator.FOR_LOOP_INNER_WHILE) + statementGenerator.expressionBodyGenerator.putLoop(ktFor, irInnerWhile) + irForBlock.addStatement(irInnerWhile) + + val hasNextCall = statementGenerator.pregenerateCall(hasNextResolvedCall) + hasNextCall.setExplicitReceiverValue(iteratorValue) + val irHasNextCall = callGenerator.generateCall(ktLoopRange, hasNextCall, IrOperator.FOR_LOOP_HAS_NEXT) + irInnerWhile.condition = irHasNextCall + + val irInnerBody = IrBlockImpl(ktFor.startOffset, ktFor.endOffset, context.builtIns.unitType, false, IrOperator.FOR_LOOP_INNER_WHILE) + irInnerWhile.body = irInnerBody + + val nextCall = statementGenerator.pregenerateCall(nextResolvedCall) + nextCall.setExplicitReceiverValue(iteratorValue) + val irNextCall = callGenerator.generateCall(ktLoopRange, nextCall, IrOperator.FOR_LOOP_NEXT) + val irLoopParameter = if (ktLoopParameter != null) { + val loopParameterDescriptor = getOrFail(BindingContext.VALUE_PARAMETER, ktLoopParameter) + IrVariableImpl(ktLoopParameter.startOffset, ktLoopParameter.endOffset, IrDeclarationOriginKind.DEFINED, + loopParameterDescriptor, irNextCall) + } + else { + scope.createTemporaryVariable(irNextCall, "loop_parameter") + } + irInnerBody.addStatement(irLoopParameter) + + if (ktLoopDestructuringParameter != null) { + statementGenerator.declareComponentVariablesInBlock(ktLoopDestructuringParameter, irInnerBody, VariableLValue(irLoopParameter)) + } + + irInnerBody.addStatement(statementGenerator.generateExpression(ktForBody)) + + return irForBlock + } } \ No newline at end of file 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 01d68d1be6b..12229b42e9b 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 @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.deparenthesize +import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue import org.jetbrains.kotlin.resolve.BindingContext @@ -76,25 +77,28 @@ class StatementGenerator( val irBlock = IrBlockImpl(multiDeclaration.startOffset, multiDeclaration.endOffset, null, false, IrOperator.SYNTHETIC_BLOCK) val ktInitializer = multiDeclaration.initializer!! - val irTmpInitializerValue = createRematerializableOrTemporary(scope, ktInitializer.genExpr(), irBlock, "container") + val containerValue = createRematerializableOrTemporary(scope, ktInitializer.genExpr(), irBlock, "container") - val irCallGenerator = CallGenerator(this) + declareComponentVariablesInBlock(multiDeclaration, irBlock, containerValue) + return irBlock + } + + fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: IntermediateValue) { + val callGenerator = CallGenerator(this) for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) val componentSubstitutedCall = pregenerateCall(componentResolvedCall) - componentSubstitutedCall.setExplicitReceiverValue(irTmpInitializerValue) + componentSubstitutedCall.setExplicitReceiverValue(containerValue) val componentVariable = getOrFail(BindingContext.VARIABLE, ktEntry) - val irComponentCall = irCallGenerator.generateCall(ktEntry.startOffset, ktEntry.endOffset, componentSubstitutedCall, - IrOperator.COMPONENT_N.withIndex(index + 1)) + val irComponentCall = callGenerator.generateCall(ktEntry.startOffset, ktEntry.endOffset, componentSubstitutedCall, + IrOperator.COMPONENT_N.withIndex(index + 1)) val irComponentVar = IrVariableImpl(ktEntry.startOffset, ktEntry.endOffset, IrDeclarationOriginKind.DEFINED, componentVariable, irComponentCall) irBlock.addStatement(irComponentVar) } - - return irBlock } override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement { @@ -273,16 +277,19 @@ class StatementGenerator( BranchingExpressionGenerator(this).generateWhenExpression(expression) override fun visitWhileExpression(expression: KtWhileExpression, data: Nothing?): IrStatement = - LoopExpressionGenerator(this).generateWhileExpression(expression) + LoopExpressionGenerator(this).generateWhileLoop(expression) override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Nothing?): IrStatement = - LoopExpressionGenerator(this).generateDoWhileExpression(expression) + LoopExpressionGenerator(this).generateDoWhileLoop(expression) + + override fun visitForExpression(expression: KtForExpression, data: Nothing?): IrStatement = + LoopExpressionGenerator(this).generateForLoop(expression) override fun visitBreakExpression(expression: KtBreakExpression, data: Nothing?): IrStatement = - LoopExpressionGenerator(this).generateBreakExpression(expression) + LoopExpressionGenerator(this).generateBreak(expression) override fun visitContinueExpression(expression: KtContinueExpression, data: Nothing?): IrStatement = - LoopExpressionGenerator(this).generateContinueExpression(expression) + LoopExpressionGenerator(this).generateContinue(expression) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/TransientReceiverValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/TransientReceiverValue.kt new file mode 100644 index 00000000000..2d3979c9dbc --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/TransientReceiverValue.kt @@ -0,0 +1,26 @@ +/* + * 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.ir.expressions.IrExpression +import org.jetbrains.kotlin.types.KotlinType + +class TransientReceiverValue(val description: String, override val type: KotlinType?): IntermediateValue { + override fun load(): IrExpression { + throw AssertionError("Transient receiver should not be instantiated: $description") + } +} diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt index aa03f939a32..dcb66dd3cc2 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrOperator.kt @@ -76,6 +76,11 @@ interface IrOperator { object WHEN_COMMA : IrOperatorImpl("WHEN_COMMA") object WHILE_LOOP : IrOperatorImpl("WHILE_LOOP") object DO_WHILE_LOOP : IrOperatorImpl("DO_WHILE_LOOP") + object FOR_LOOP : IrOperatorImpl("FOR_LOOP") + object FOR_LOOP_ITERATOR : IrOperatorImpl("FOR_LOOP_ITERATOR") + object FOR_LOOP_INNER_WHILE : IrOperatorImpl("FOR_LOOP_INNER_WHILE") + object FOR_LOOP_HAS_NEXT : IrOperatorImpl("FOR_LOOP_HAS_NEXT") + object FOR_LOOP_NEXT : IrOperatorImpl("FOR_LOOP_NEXT") data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") { companion object { diff --git a/compiler/testData/ir/irText/for.kt b/compiler/testData/ir/irText/for.kt new file mode 100644 index 00000000000..bdeba41db84 --- /dev/null +++ b/compiler/testData/ir/irText/for.kt @@ -0,0 +1,13 @@ +fun testIterable(ss: List) { + for (s in ss) { + println(s) + } +} + +fun testDestructuring(pp: List>) { + for ((i, s) in pp) { + println(i) + println(s) + } +} + diff --git a/compiler/testData/ir/irText/for.txt b/compiler/testData/ir/irText/for.txt new file mode 100644 index 00000000000..9fdb1fe8a18 --- /dev/null +++ b/compiler/testData/ir/irText/for.txt @@ -0,0 +1,43 @@ +IrFile /for.kt + IrFunction public fun testIterable(/*0*/ ss: kotlin.collections.List): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + CALL .println type=kotlin.Unit operator=null + message: GET_VAR s type=kotlin.String operator=null + IrFunction public fun testDestructuring(/*0*/ pp: kotlin.collections.List>): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator> + CALL .iterator type=kotlin.collections.Iterator> operator=FOR_LOOP_ITERATOR + $this: GET_VAR pp type=kotlin.collections.List> operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator> operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val tmp1_loop_parameter: kotlin.Pair + CALL .next type=kotlin.Pair operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator> operator=null + VAR val i: kotlin.Int + CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1) + $this: GET_VAR tmp1_loop_parameter type=kotlin.Pair operator=null + VAR val s: kotlin.String + CALL .component2 type=kotlin.String operator=COMPONENT_N(index=2) + $this: GET_VAR tmp1_loop_parameter type=kotlin.Pair operator=null + BLOCK type= hasResult=false operator=null + CALL .println type=kotlin.Unit operator=null + message: GET_VAR i type=kotlin.Int operator=null + CALL .println type=kotlin.Unit operator=null + message: GET_VAR s type=kotlin.String operator=null diff --git a/compiler/testData/ir/irText/forWithBreakContinue.kt b/compiler/testData/ir/irText/forWithBreakContinue.kt new file mode 100644 index 00000000000..7e7db71d20b --- /dev/null +++ b/compiler/testData/ir/irText/forWithBreakContinue.kt @@ -0,0 +1,33 @@ +fun testForBreak1(ss: List) { + for (s in ss) { + break + } +} + +fun testForBreak2(ss: List) { + OUTER@for (s1 in ss) { + INNER@for (s2 in ss) { + break@OUTER + break@INNER + break + } + break@OUTER + } +} + +fun testForContinue1(ss: List) { + for (s in ss) { + continue + } +} + +fun testForContinue2(ss: List) { + OUTER@for (s1 in ss) { + INNER@for (s2 in ss) { + continue@OUTER + continue@INNER + continue + } + continue@OUTER + } +} diff --git a/compiler/testData/ir/irText/forWithBreakContinue.txt b/compiler/testData/ir/irText/forWithBreakContinue.txt new file mode 100644 index 00000000000..8a2721b7121 --- /dev/null +++ b/compiler/testData/ir/irText/forWithBreakContinue.txt @@ -0,0 +1,95 @@ +IrFile /forWithBreakContinue.kt + IrFunction public fun testForBreak1(/*0*/ ss: kotlin.collections.List): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + BREAK loop.operator=FOR_LOOP_INNER_WHILE depth=0 + IrFunction public fun testForBreak2(/*0*/ ss: kotlin.collections.List): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s1: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp1_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp1_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s2: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp1_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + BREAK loop.operator=FOR_LOOP_INNER_WHILE depth=1 + BREAK loop.operator=FOR_LOOP_INNER_WHILE depth=0 + BREAK loop.operator=FOR_LOOP_INNER_WHILE depth=0 + BREAK loop.operator=FOR_LOOP_INNER_WHILE depth=0 + IrFunction public fun testForContinue1(/*0*/ ss: kotlin.collections.List): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + CONTINUE loop.operator=FOR_LOOP_INNER_WHILE depth=0 + IrFunction public fun testForContinue2(/*0*/ ss: kotlin.collections.List): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s1: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp0_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp1_iterator: kotlin.collections.Iterator + CALL .iterator type=kotlin.collections.Iterator operator=FOR_LOOP_ITERATOR + $this: GET_VAR ss type=kotlin.collections.List operator=null + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: GET_VAR tmp1_iterator type=kotlin.collections.Iterator operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val s2: kotlin.String + CALL .next type=kotlin.String operator=FOR_LOOP_NEXT + $this: GET_VAR tmp1_iterator type=kotlin.collections.Iterator operator=null + BLOCK type= hasResult=false operator=null + CONTINUE loop.operator=FOR_LOOP_INNER_WHILE depth=1 + CONTINUE loop.operator=FOR_LOOP_INNER_WHILE depth=0 + CONTINUE loop.operator=FOR_LOOP_INNER_WHILE depth=0 + CONTINUE loop.operator=FOR_LOOP_INNER_WHILE depth=0 diff --git a/compiler/testData/ir/irText/forWithImplicitReceivers.kt b/compiler/testData/ir/irText/forWithImplicitReceivers.kt new file mode 100644 index 00000000000..4461b3bb33c --- /dev/null +++ b/compiler/testData/ir/irText/forWithImplicitReceivers.kt @@ -0,0 +1,15 @@ +object FiveTimes + +class IntCell(var value: Int) + +interface IReceiver { + operator fun FiveTimes.iterator() = IntCell(5) + operator fun IntCell.hasNext() = value > 0 + operator fun IntCell.next() = value-- +} + +fun IReceiver.test() { + for (i in FiveTimes) { + println(i) + } +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/forWithImplicitReceivers.txt b/compiler/testData/ir/irText/forWithImplicitReceivers.txt new file mode 100644 index 00000000000..777610f5666 --- /dev/null +++ b/compiler/testData/ir/irText/forWithImplicitReceivers.txt @@ -0,0 +1,24 @@ +IrFile /forWithImplicitReceivers.kt + DUMMY FiveTimes + DUMMY IntCell + DUMMY IReceiver + IrFunction public fun IReceiver.test(): kotlin.Unit + IrExpressionBody + BLOCK type= hasResult=false operator=null + BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP + VAR val tmp0_iterator: IntCell + CALL .iterator type=IntCell operator=FOR_LOOP_ITERATOR + $this: $RECEIVER of: test type=IReceiver + $receiver: GET_OBJECT FiveTimes type=FiveTimes + WHILE operator=FOR_LOOP_INNER_WHILE + condition: CALL .hasNext type=kotlin.Boolean operator=FOR_LOOP_HAS_NEXT + $this: $RECEIVER of: test type=IReceiver + $receiver: GET_VAR tmp0_iterator type=IntCell operator=null + body: BLOCK type=kotlin.Unit hasResult=false operator=FOR_LOOP_INNER_WHILE + VAR val i: kotlin.Int + CALL .next type=kotlin.Int operator=FOR_LOOP_NEXT + $this: $RECEIVER of: test type=IReceiver + $receiver: GET_VAR tmp0_iterator type=IntCell operator=null + BLOCK type= hasResult=false operator=null + CALL .println type=kotlin.Unit operator=null + message: GET_VAR i type=kotlin.Int operator=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 68959e1792f..1ebf7cec505 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -137,6 +137,24 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("for.kt") + public void testFor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/for.kt"); + doTest(fileName); + } + + @TestMetadata("forWithBreakContinue.kt") + public void testForWithBreakContinue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/forWithBreakContinue.kt"); + doTest(fileName); + } + + @TestMetadata("forWithImplicitReceivers.kt") + public void testForWithImplicitReceivers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/forWithImplicitReceivers.kt"); + doTest(fileName); + } + @TestMetadata("identity.kt") public void testIdentity() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/identity.kt");