Handle withIndex() on arrays and CharSequences in ForLoopsLowering.
This commit is contained in:
committed by
max-kammerer
parent
735535dd5a
commit
a54d9482dd
+152
-73
@@ -11,11 +11,12 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
@@ -117,24 +118,53 @@ private class RangeLoopTransformer(
|
|||||||
) : IrElementTransformerVoidWithContext() {
|
) : IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
private val symbols = context.ir.symbols
|
private val symbols = context.ir.symbols
|
||||||
private val iteratorToLoopHeader = mutableMapOf<IrVariableSymbol, ForLoopHeader>()
|
|
||||||
private val headerInfoBuilder = HeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
private val headerInfoBuilder = HeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
||||||
private val headerProcessor = HeaderProcessor(context, headerInfoBuilder, this::getScopeOwnerSymbol)
|
private val headerProcessor = HeaderProcessor(context, headerInfoBuilder, this::getScopeOwnerSymbol)
|
||||||
|
|
||||||
fun getScopeOwnerSymbol() = currentScope!!.scope.scopeOwnerSymbol
|
fun getScopeOwnerSymbol() = currentScope!!.scope.scopeOwnerSymbol
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable): IrStatement {
|
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||||
val initializer = declaration.initializer
|
// LoopExpressionGenerator in psi2ir lowers `for (loopVar in <someIterable>) { // Loop body }` into an IrBlock with origin FOR_LOOP.
|
||||||
if (initializer == null || initializer !is IrCall) {
|
// This block has 2 statements:
|
||||||
return super.visitVariable(declaration)
|
//
|
||||||
|
// // #1: The "header"
|
||||||
|
// val it = <someIterable>.iterator()
|
||||||
|
//
|
||||||
|
// // #2: The inner while loop
|
||||||
|
// while (it.hasNext()) {
|
||||||
|
// val loopVar = it.next()
|
||||||
|
// // Loop body
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We primarily need to determine HOW to optimize the for loop from the iterable expression in the header (e.g., if it's a
|
||||||
|
// `withIndex()` call, a progression such as `10 downTo 1`). However in some cases (e.g., for `withIndex()`), we also need to
|
||||||
|
// examine the while loop to determine if we CAN optimize the loop.
|
||||||
|
if (expression.origin != IrStatementOrigin.FOR_LOOP) {
|
||||||
|
return super.visitBlock(expression) // Not a for-loop block.
|
||||||
}
|
}
|
||||||
return when (initializer.origin) {
|
|
||||||
IrStatementOrigin.FOR_LOOP_ITERATOR ->
|
with(expression.statements) {
|
||||||
processHeader(declaration)
|
assert(size == 2) { "Expected 2 statements in for-loop block, was:\n${expression.dump()}" }
|
||||||
IrStatementOrigin.FOR_LOOP_NEXT ->
|
val iteratorVariable = get(0) as IrVariable
|
||||||
processNext(declaration)
|
assert(iteratorVariable.origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR) { "Expected FOR_LOOP_ITERATOR origin for iterator variable, was:\n${iteratorVariable.dump()}" }
|
||||||
else -> null
|
val loopHeader = headerProcessor.extractHeader(iteratorVariable)
|
||||||
} ?: super.visitVariable(declaration)
|
?: return super.visitBlock(expression) // The iterable in the header is not supported.
|
||||||
|
val loweredHeader = lowerHeader(iteratorVariable, loopHeader)
|
||||||
|
|
||||||
|
val oldLoop = get(1) as IrWhileLoop
|
||||||
|
assert(oldLoop.origin == IrStatementOrigin.FOR_LOOP_INNER_WHILE) { "Expected FOR_LOOP_INNER_WHILE origin for while loop, was:\n${oldLoop.dump()}" }
|
||||||
|
val (newLoop, loopReplacementExpression) = lowerWhileLoop(oldLoop, loopHeader)
|
||||||
|
?: return super.visitBlock(expression) // Cannot lower the loop.
|
||||||
|
|
||||||
|
// We can lower both the header and while loop.
|
||||||
|
// Update mapping from old to new loop so we can later update references in break/continue.
|
||||||
|
oldLoopToNewLoop[oldLoop] = newLoop
|
||||||
|
|
||||||
|
set(0, loweredHeader)
|
||||||
|
set(1, loopReplacementExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.visitBlock(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,74 +174,53 @@ private class RangeLoopTransformer(
|
|||||||
*
|
*
|
||||||
* Returns null if the for-loop cannot be lowered.
|
* Returns null if the for-loop cannot be lowered.
|
||||||
*/
|
*/
|
||||||
private fun processHeader(variable: IrVariable): IrStatement? {
|
private fun lowerHeader(variable: IrVariable, loopHeader: ForLoopHeader): IrStatement {
|
||||||
assert(variable.symbol !in iteratorToLoopHeader)
|
|
||||||
val forLoopInfo = headerProcessor.processHeader(variable)
|
|
||||||
?: return null // If the for-loop cannot be lowered.
|
|
||||||
iteratorToLoopHeader[variable.symbol] = forLoopInfo
|
|
||||||
|
|
||||||
// Lower into a composite with additional statements (e.g., induction variable) used in the loop condition and body.
|
// Lower into a composite with additional statements (e.g., induction variable) used in the loop condition and body.
|
||||||
return IrCompositeImpl(
|
return IrCompositeImpl(
|
||||||
variable.startOffset,
|
variable.startOffset,
|
||||||
variable.endOffset,
|
variable.endOffset,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
null,
|
null,
|
||||||
forLoopInfo.loopInitStatements
|
loopHeader.loopInitStatements
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhileLoop(loop: IrWhileLoop): IrExpression {
|
private fun lowerWhileLoop(loop: IrWhileLoop, loopHeader: ForLoopHeader): LoopReplacement? {
|
||||||
if (loop.origin != IrStatementOrigin.FOR_LOOP_INNER_WHILE) {
|
val loopBodyStatements = (loop.body as? IrContainerExpression)?.statements ?: return null
|
||||||
return super.visitWhileLoop(loop)
|
val (mainLoopVariable, mainLoopVariableIndex, loopVariableComponents, loopVariableComponentIndices) = gatherLoopVariableInfo(
|
||||||
}
|
loopBodyStatements
|
||||||
|
)
|
||||||
|
|
||||||
with(context.createIrBuilder(getScopeOwnerSymbol(), loop.startOffset, loop.endOffset)) {
|
if (loopHeader.consumesLoopVariableComponents && mainLoopVariable.origin != IrDeclarationOrigin.IR_TEMPORARY_VARIABLE) {
|
||||||
// Visit the loop body to process the "next" statement and lower nested loops.
|
// We determine if there is a destructuring declaration by checking if the main loop variable is temporary.
|
||||||
// Processing the "next" statement is necessary for building loops that need to
|
// This is somewhat brittle and depends on the implementation of LoopExpressionGenerator in psi2ir.
|
||||||
// reference the loop variable in the loop condition.
|
//
|
||||||
val newBody = loop.body?.transform(this@RangeLoopTransformer, null)?.let {
|
// 1. If the loop is `for ((i, v) in arr.withIndex() {}`), the loop body looks like this:
|
||||||
if (it is IrContainerExpression && !it.isTransparentScope) {
|
//
|
||||||
IrCompositeImpl(startOffset, endOffset, it.type, it.origin, it.statements)
|
// val tmp_loopParameter = it.next() // origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
} else {
|
// val i = tmp_loopParameter.component1()
|
||||||
it
|
// val v = tmp_loopParameter.component2()
|
||||||
}
|
//
|
||||||
}
|
// 2. If the loop is `for (iv in arr.withIndex() { val (i, v) = iv }`), the loop body looks like this:
|
||||||
|
//
|
||||||
val loopHeader = getLoopHeader(loop.condition)
|
// val iv = it.next() // origin != IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
?: return super.visitWhileLoop(loop) // If the for-loop cannot be lowered.
|
// val i = iv.component1()
|
||||||
val (newLoop, replacementExpression) = loopHeader.buildLoop(this, loop, newBody)
|
// val v = iv.component2()
|
||||||
|
//
|
||||||
// Update mapping from old to new loop so we can later update references in break/continue.
|
// 3. If the loop is `for ((_, _) in arr.withIndex() {}`), the loop body looks like this:
|
||||||
oldLoopToNewLoop[loop] = newLoop
|
//
|
||||||
|
// val tmp_loopParameter = it.next() // origin == IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
return replacementExpression
|
// // No component variables
|
||||||
}
|
//
|
||||||
}
|
// 4. If the loop is `for (iv in arr.withIndex() {}`), the loop body looks like this:
|
||||||
|
//
|
||||||
private fun getLoopHeader(expression: IrExpression): ForLoopHeader? {
|
// val iv = it.next() // origin != IrDeclarationOrigin.IR_TEMPORARY_VARIABLE
|
||||||
if (expression !is IrCall
|
// // No component variables
|
||||||
|| (expression.origin != IrStatementOrigin.FOR_LOOP_HAS_NEXT
|
//
|
||||||
&& expression.origin != IrStatementOrigin.FOR_LOOP_NEXT)
|
// The only way to distinguish between #1 and #2, and between #3 and #4 is to check the origin of the main loop variable.
|
||||||
) {
|
// We need to distinguish between these because we intend to only optimize #1 and #3.
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val iterator = expression.dispatchReceiver as IrGetValue
|
|
||||||
|
|
||||||
// Return null if we didn't lower the corresponding header.
|
|
||||||
return iteratorToLoopHeader[iterator.symbol]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lowers the "next" statement that stores the next element in the iterable into the
|
|
||||||
* loop variable, e.g., `val i = it.next()`.
|
|
||||||
*
|
|
||||||
* Returns null if there was no stored [ForLoopHeader] corresponding to the given "next"
|
|
||||||
* statement.
|
|
||||||
*/
|
|
||||||
private fun processNext(variable: IrVariable): IrExpression? {
|
|
||||||
val initializer = variable.initializer as IrCall
|
|
||||||
val forLoopInfo = getLoopHeader(initializer)
|
|
||||||
?: return null // If the for-loop cannot be lowered.
|
|
||||||
|
|
||||||
// The "next" statement (at the top of the loop):
|
// The "next" statement (at the top of the loop):
|
||||||
//
|
//
|
||||||
@@ -221,14 +230,84 @@ private class RangeLoopTransformer(
|
|||||||
//
|
//
|
||||||
// val i = inductionVariable // For progressions, or `array[inductionVariable]` for arrays
|
// val i = inductionVariable // For progressions, or `array[inductionVariable]` for arrays
|
||||||
// inductionVariable = inductionVariable + step
|
// inductionVariable = inductionVariable + step
|
||||||
return with(context.createIrBuilder(getScopeOwnerSymbol(), initializer.startOffset, initializer.endOffset)) {
|
val initializer = mainLoopVariable.initializer as IrCall
|
||||||
|
val replacement = with(context.createIrBuilder(getScopeOwnerSymbol(), initializer.startOffset, initializer.endOffset)) {
|
||||||
IrCompositeImpl(
|
IrCompositeImpl(
|
||||||
variable.startOffset,
|
mainLoopVariable.startOffset,
|
||||||
variable.endOffset,
|
mainLoopVariable.endOffset,
|
||||||
context.irBuiltIns.unitType,
|
context.irBuiltIns.unitType,
|
||||||
IrStatementOrigin.FOR_LOOP_NEXT,
|
IrStatementOrigin.FOR_LOOP_NEXT,
|
||||||
forLoopInfo.initializeIteration(variable, symbols, this)
|
loopHeader.initializeIteration(mainLoopVariable, loopVariableComponents, symbols, this)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the main loop variable components if they are consumed in initializing the iteration.
|
||||||
|
if (loopHeader.consumesLoopVariableComponents) {
|
||||||
|
for (index in loopVariableComponentIndices.asReversed()) {
|
||||||
|
assert(index > mainLoopVariableIndex)
|
||||||
|
loopBodyStatements.removeAt(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loopBodyStatements[mainLoopVariableIndex] = replacement
|
||||||
|
|
||||||
|
// Variables in the loop body may be used in the loop condition, so ensure the body scope is transparent (i.e., an IrComposite).
|
||||||
|
val newBody = loop.body?.let {
|
||||||
|
if (it is IrContainerExpression && !it.isTransparentScope) {
|
||||||
|
IrCompositeImpl(loop.startOffset, loop.endOffset, it.type, it.origin, it.statements)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loopHeader.buildLoop(context.createIrBuilder(getScopeOwnerSymbol(), loop.startOffset, loop.endOffset), loop, newBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class LoopVariableInfo(
|
||||||
|
val mainLoopVariable: IrVariable,
|
||||||
|
val mainLoopVariableIndex: Int,
|
||||||
|
val loopVariableComponents: Map<Int, IrVariable>,
|
||||||
|
val loopVariableComponentIndices: List<Int>
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun gatherLoopVariableInfo(statements: MutableList<IrStatement>): LoopVariableInfo {
|
||||||
|
// The "next" statement (at the top of the loop) looks something like:
|
||||||
|
//
|
||||||
|
// val i = it.next()
|
||||||
|
//
|
||||||
|
// In the case of loops with a destructuring declaration (e.g., `for ((i, v) in arr.withIndex()`), the "next" statement includes
|
||||||
|
// component variables:
|
||||||
|
//
|
||||||
|
// val tmp_loopParameter = it.next()
|
||||||
|
// val i = tmp_loopParameter.component1()
|
||||||
|
// val v = tmp_loopParameter.component2()
|
||||||
|
//
|
||||||
|
// We find the main loop variable and all the component variables that are used to initialize the iteration.
|
||||||
|
var mainLoopVariable: IrVariable? = null
|
||||||
|
var mainLoopVariableIndex = -1
|
||||||
|
val loopVariableComponents = mutableMapOf<Int, IrVariable>()
|
||||||
|
val loopVariableComponentIndices = mutableListOf<Int>()
|
||||||
|
for ((i, stmt) in statements.withIndex()) {
|
||||||
|
if (stmt !is IrVariable) continue
|
||||||
|
val initializer = stmt.initializer as? IrCall
|
||||||
|
when (val origin = initializer?.origin) {
|
||||||
|
IrStatementOrigin.FOR_LOOP_NEXT -> {
|
||||||
|
mainLoopVariable = stmt
|
||||||
|
mainLoopVariableIndex = i
|
||||||
|
}
|
||||||
|
is IrStatementOrigin.COMPONENT_N -> {
|
||||||
|
if (mainLoopVariable != null &&
|
||||||
|
(initializer.dispatchReceiver as? IrGetValue)?.symbol == mainLoopVariable.symbol
|
||||||
|
) {
|
||||||
|
loopVariableComponents[origin.index] = stmt
|
||||||
|
loopVariableComponentIndices.add(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNotNull(mainLoopVariable) { "No 'next' statement in for-loop" }
|
||||||
|
assert(mainLoopVariableIndex >= 0)
|
||||||
|
|
||||||
|
return LoopVariableInfo(mainLoopVariable, mainLoopVariableIndex, loopVariableComponents, loopVariableComponentIndices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+18
-5
@@ -203,6 +203,15 @@ internal class IndexedGetHeaderInfo(
|
|||||||
override fun asReversed(): HeaderInfo? = null
|
override fun asReversed(): HeaderInfo? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a for-loop over an iterable returned by `withIndex()`.
|
||||||
|
*/
|
||||||
|
internal class WithIndexHeaderInfo(val nestedInfo: HeaderInfo) : HeaderInfo() {
|
||||||
|
// We cannot easily reverse `withIndex()` so we do not attempt to handle it. We would have to start from the last value of the index,
|
||||||
|
// easily calculable (or even impossible) in most cases.
|
||||||
|
override fun asReversed(): HeaderInfo? = null
|
||||||
|
}
|
||||||
|
|
||||||
/** Matches an iterable expression and builds a [HeaderInfo] from the expression. */
|
/** Matches an iterable expression and builds a [HeaderInfo] from the expression. */
|
||||||
internal interface HeaderInfoHandler<E : IrExpression, D> {
|
internal interface HeaderInfoHandler<E : IrExpression, D> {
|
||||||
/** Returns true if the handler can build a [HeaderInfo] from the iterable expression. */
|
/** Returns true if the handler can build a [HeaderInfo] from the iterable expression. */
|
||||||
@@ -263,7 +272,10 @@ internal class HeaderInfoBuilder(context: CommonBackendContext, private val scop
|
|||||||
StepHandler(context, this)
|
StepHandler(context, this)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val reversedHandler = ReversedHandler(context, this)
|
private val callHandlers = listOf(
|
||||||
|
ReversedHandler(context, this),
|
||||||
|
WithIndexHandler(context, this)
|
||||||
|
)
|
||||||
|
|
||||||
// NOTE: StringIterationHandler MUST come before CharSequenceIterationHandler.
|
// NOTE: StringIterationHandler MUST come before CharSequenceIterationHandler.
|
||||||
// String is subtype of CharSequence and therefore its handler is more specialized.
|
// String is subtype of CharSequence and therefore its handler is more specialized.
|
||||||
@@ -278,10 +290,11 @@ internal class HeaderInfoBuilder(context: CommonBackendContext, private val scop
|
|||||||
|
|
||||||
/** Builds a [HeaderInfo] for iterable expressions that are calls (e.g., `.reversed()`, `.indices`. */
|
/** Builds a [HeaderInfo] for iterable expressions that are calls (e.g., `.reversed()`, `.indices`. */
|
||||||
override fun visitCall(iterable: IrCall, iteratorCall: IrCall?): HeaderInfo? {
|
override fun visitCall(iterable: IrCall, iteratorCall: IrCall?): HeaderInfo? {
|
||||||
// Return the HeaderInfo from the first successful match. First, try to match a `reversed()` call.
|
// Return the HeaderInfo from the first successful match.
|
||||||
val reversedHeaderInfo = reversedHandler.handle(iterable, iteratorCall, null, scopeOwnerSymbol())
|
// First, try to match a `reversed()` or `withIndex()` call.
|
||||||
if (reversedHeaderInfo != null)
|
val callHeaderInfo = callHandlers.firstNotNullResult { it.handle(iterable, iteratorCall, null, scopeOwnerSymbol()) }
|
||||||
return reversedHeaderInfo
|
if (callHeaderInfo != null)
|
||||||
|
return callHeaderInfo
|
||||||
|
|
||||||
// Try to match a call to build a progression (e.g., `.indices`, `downTo`).
|
// Try to match a call to build a progression (e.g., `.indices`, `downTo`).
|
||||||
val progressionType = ProgressionType.fromIrType(iterable.type, symbols)
|
val progressionType = ProgressionType.fromIrType(iterable.type, symbols)
|
||||||
|
|||||||
+189
-25
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.builders.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
|
||||||
@@ -41,9 +42,16 @@ internal interface ForLoopHeader {
|
|||||||
/** Statements used to initialize the entire loop (e.g., declare induction variable). */
|
/** Statements used to initialize the entire loop (e.g., declare induction variable). */
|
||||||
val loopInitStatements: List<IrStatement>
|
val loopInitStatements: List<IrStatement>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not [initializeIteration] consumes the loop variable components assigned to it.
|
||||||
|
* If true, the component variables should be removed from the un-lowered loop.
|
||||||
|
*/
|
||||||
|
val consumesLoopVariableComponents: Boolean
|
||||||
|
|
||||||
/** Statements used to initialize an iteration of the loop (e.g., assign loop variable). */
|
/** Statements used to initialize an iteration of the loop (e.g., assign loop variable). */
|
||||||
fun initializeIteration(
|
fun initializeIteration(
|
||||||
loopVariable: IrVariable,
|
loopVariable: IrVariable?,
|
||||||
|
loopVariableComponents: Map<Int, IrVariable>,
|
||||||
symbols: Symbols<CommonBackendContext>,
|
symbols: Symbols<CommonBackendContext>,
|
||||||
builder: DeclarationIrBuilder
|
builder: DeclarationIrBuilder
|
||||||
): List<IrStatement>
|
): List<IrStatement>
|
||||||
@@ -52,15 +60,17 @@ internal interface ForLoopHeader {
|
|||||||
fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?): LoopReplacement
|
fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?): LoopReplacement
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class NumericForLoopHeader(
|
internal abstract class NumericForLoopHeader<T : NumericHeaderInfo>(
|
||||||
headerInfo: NumericHeaderInfo,
|
protected val headerInfo: T,
|
||||||
builder: DeclarationIrBuilder,
|
builder: DeclarationIrBuilder,
|
||||||
protected val isLastInclusive: Boolean
|
protected val isLastInclusive: Boolean
|
||||||
) : ForLoopHeader {
|
) : ForLoopHeader {
|
||||||
|
|
||||||
protected val inductionVariable: IrVariable
|
override val consumesLoopVariableComponents = false
|
||||||
|
|
||||||
|
val inductionVariable: IrVariable
|
||||||
|
val stepVariable: IrVariable
|
||||||
protected val lastVariableIfCanCacheLast: IrVariable?
|
protected val lastVariableIfCanCacheLast: IrVariable?
|
||||||
protected val stepVariable: IrVariable
|
|
||||||
protected val lastExpression: IrExpression
|
protected val lastExpression: IrExpression
|
||||||
// Always copy `lastExpression` is it may be used in multiple conditions.
|
// Always copy `lastExpression` is it may be used in multiple conditions.
|
||||||
get() = field.deepCopyWithSymbols()
|
get() = field.deepCopyWithSymbols()
|
||||||
@@ -120,11 +130,6 @@ internal abstract class NumericForLoopHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This cannot be declared and initialized directly in the constructor. At the time of the base class (ForLoopHeader) constructor
|
|
||||||
// execution, the `headerInfo` property overridden in the derived class (e.g., NumericForLoopHeader) is not yet initialized.
|
|
||||||
// Therefore, we must use the `headerInfo` constructor parameter in the "init" block above instead of using the property.
|
|
||||||
protected open val headerInfo: NumericHeaderInfo = headerInfo
|
|
||||||
|
|
||||||
private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression) =
|
private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression) =
|
||||||
if (expression.type is IrSimpleType && expression.type.isNullable()) {
|
if (expression.type is IrSimpleType && expression.type.isNullable()) {
|
||||||
irImplicitCast(expression, expression.type.makeNotNull())
|
irImplicitCast(expression, expression.type.makeNotNull())
|
||||||
@@ -204,9 +209,9 @@ internal abstract class NumericForLoopHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class ProgressionLoopHeader(
|
internal class ProgressionLoopHeader(
|
||||||
override val headerInfo: ProgressionHeaderInfo,
|
headerInfo: ProgressionHeaderInfo,
|
||||||
builder: DeclarationIrBuilder
|
builder: DeclarationIrBuilder
|
||||||
) : NumericForLoopHeader(headerInfo, builder, isLastInclusive = true) {
|
) : NumericForLoopHeader<ProgressionHeaderInfo>(headerInfo, builder, isLastInclusive = true) {
|
||||||
|
|
||||||
// For this loop:
|
// For this loop:
|
||||||
//
|
//
|
||||||
@@ -227,13 +232,28 @@ internal class ProgressionLoopHeader(
|
|||||||
|
|
||||||
private var loopVariable: IrVariable? = null
|
private var loopVariable: IrVariable? = null
|
||||||
|
|
||||||
override fun initializeIteration(loopVariable: IrVariable, symbols: Symbols<CommonBackendContext>, builder: DeclarationIrBuilder) =
|
override fun initializeIteration(
|
||||||
|
loopVariable: IrVariable?,
|
||||||
|
loopVariableComponents: Map<Int, IrVariable>,
|
||||||
|
symbols: Symbols<CommonBackendContext>,
|
||||||
|
builder: DeclarationIrBuilder
|
||||||
|
) =
|
||||||
with(builder) {
|
with(builder) {
|
||||||
this@ProgressionLoopHeader.loopVariable = loopVariable
|
// loopVariable is used in the loop condition if it can overflow. If no loopVariable was provided, create one.
|
||||||
|
this@ProgressionLoopHeader.loopVariable = if (headerInfo.canOverflow && loopVariable == null) {
|
||||||
|
scope.createTemporaryVariable(
|
||||||
|
irGet(inductionVariable),
|
||||||
|
nameHint = "loopVariable",
|
||||||
|
isMutable = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
loopVariable?.initializer = irGet(inductionVariable)
|
||||||
|
loopVariable
|
||||||
|
}
|
||||||
|
|
||||||
// loopVariable = inductionVariable
|
// loopVariable = inductionVariable
|
||||||
// inductionVariable = inductionVariable + step
|
// inductionVariable = inductionVariable + step
|
||||||
loopVariable.initializer = irGet(inductionVariable)
|
listOfNotNull(loopVariable, incrementInductionVariable(this))
|
||||||
listOf(loopVariable, incrementInductionVariable(this))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?) =
|
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?) =
|
||||||
@@ -259,9 +279,9 @@ internal class ProgressionLoopHeader(
|
|||||||
//
|
//
|
||||||
// if (inductionVar <= last) {
|
// if (inductionVar <= last) {
|
||||||
// do {
|
// do {
|
||||||
// val loopVar = inductionVar
|
// val loopVar = inductionVar
|
||||||
// inductionVar += step
|
// inductionVar += step
|
||||||
// // Loop body
|
// // Loop body
|
||||||
// } while (inductionVar <= last)
|
// } while (inductionVar <= last)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
@@ -283,21 +303,29 @@ internal class ProgressionLoopHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class IndexedGetLoopHeader(
|
internal class IndexedGetLoopHeader(
|
||||||
override val headerInfo: IndexedGetHeaderInfo,
|
headerInfo: IndexedGetHeaderInfo,
|
||||||
builder: DeclarationIrBuilder
|
builder: DeclarationIrBuilder
|
||||||
) : NumericForLoopHeader(headerInfo, builder, isLastInclusive = false) {
|
) : NumericForLoopHeader<IndexedGetHeaderInfo>(headerInfo, builder, isLastInclusive = false) {
|
||||||
|
|
||||||
override val loopInitStatements = listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable)
|
override val loopInitStatements = listOfNotNull(headerInfo.objectVariable, inductionVariable, lastVariableIfCanCacheLast, stepVariable)
|
||||||
|
|
||||||
override fun initializeIteration(loopVariable: IrVariable, symbols: Symbols<CommonBackendContext>, builder: DeclarationIrBuilder) =
|
override fun initializeIteration(
|
||||||
|
loopVariable: IrVariable?,
|
||||||
|
loopVariableComponents: Map<Int, IrVariable>,
|
||||||
|
symbols: Symbols<CommonBackendContext>,
|
||||||
|
builder: DeclarationIrBuilder
|
||||||
|
) =
|
||||||
with(builder) {
|
with(builder) {
|
||||||
// loopVariable = objectVariable[inductionVariable]
|
// loopVariable = objectVariable[inductionVariable]
|
||||||
val indexedGetFun = with(headerInfo.expressionHandler) { headerInfo.objectVariable.type.getFunction }
|
val indexedGetFun = with(headerInfo.expressionHandler) { headerInfo.objectVariable.type.getFunction }
|
||||||
loopVariable.initializer = irCall(indexedGetFun).apply {
|
val get = irCall(indexedGetFun).apply {
|
||||||
dispatchReceiver = irGet(headerInfo.objectVariable)
|
dispatchReceiver = irGet(headerInfo.objectVariable)
|
||||||
putValueArgument(0, irGet(inductionVariable))
|
putValueArgument(0, irGet(inductionVariable))
|
||||||
}
|
}
|
||||||
listOf(loopVariable, incrementInductionVariable(this))
|
loopVariable?.initializer = get
|
||||||
|
// Even if there is no loop variable, we always want to call `get()` as it may have side-effects.
|
||||||
|
// The un-lowered loop always calls `get()` on each iteration.
|
||||||
|
listOf(loopVariable ?: get) + incrementInductionVariable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?): LoopReplacement = with(builder) {
|
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?): LoopReplacement = with(builder) {
|
||||||
@@ -319,6 +347,141 @@ internal class IndexedGetLoopHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class WithIndexLoopHeader(
|
||||||
|
private val headerInfo: WithIndexHeaderInfo,
|
||||||
|
builder: DeclarationIrBuilder
|
||||||
|
) : ForLoopHeader {
|
||||||
|
|
||||||
|
private val nestedLoopHeader: ForLoopHeader
|
||||||
|
private val indexVariable: IrVariable
|
||||||
|
private val ownsIndexVariable: Boolean
|
||||||
|
|
||||||
|
init {
|
||||||
|
with(builder) {
|
||||||
|
// To build the optimized/lowered `for` loop over a `withIndex()` call, we first need the header for the underlying iterable so
|
||||||
|
// so that we know how to build the loop for that iterable. More info in comments in initializeIteration().
|
||||||
|
nestedLoopHeader = when (val nestedInfo = headerInfo.nestedInfo) {
|
||||||
|
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(nestedInfo, builder)
|
||||||
|
is ProgressionHeaderInfo -> ProgressionLoopHeader(nestedInfo, builder)
|
||||||
|
is WithIndexHeaderInfo -> throw IllegalStateException("Nested WithIndexHeaderInfo not allowed for WithIndexLoopHeader")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not build own indexVariable if the nested loop header has an inductionVariable == 0 and step == 1.
|
||||||
|
// This is the case when the underlying iterable is an array, CharSequence, or a progression from 0 with step 1.
|
||||||
|
// We can use the induction variable from the underlying iterable as the index variable, since it progresses in the same way.
|
||||||
|
if (nestedLoopHeader is NumericForLoopHeader<*> &&
|
||||||
|
nestedLoopHeader.inductionVariable.type.isInt() &&
|
||||||
|
nestedLoopHeader.inductionVariable.initializer?.constLongValue == 0L &&
|
||||||
|
nestedLoopHeader.stepVariable.initializer?.constLongValue == 1L
|
||||||
|
) {
|
||||||
|
indexVariable = nestedLoopHeader.inductionVariable
|
||||||
|
ownsIndexVariable = false
|
||||||
|
} else {
|
||||||
|
indexVariable = scope.createTemporaryVariable(
|
||||||
|
irInt(0),
|
||||||
|
nameHint = "index",
|
||||||
|
isMutable = true
|
||||||
|
)
|
||||||
|
ownsIndexVariable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the index variable to the statements from the nested loop header.
|
||||||
|
override val loopInitStatements = nestedLoopHeader.loopInitStatements.let { if (ownsIndexVariable) it + indexVariable else it }
|
||||||
|
|
||||||
|
override val consumesLoopVariableComponents = true
|
||||||
|
|
||||||
|
override fun initializeIteration(
|
||||||
|
loopVariable: IrVariable?,
|
||||||
|
loopVariableComponents: Map<Int, IrVariable>,
|
||||||
|
symbols: Symbols<CommonBackendContext>,
|
||||||
|
builder: DeclarationIrBuilder
|
||||||
|
) =
|
||||||
|
with(builder) {
|
||||||
|
// The `withIndex()` extension function returns a lazy Iterable that wraps each element of the underlying iterable (e.g., array,
|
||||||
|
// progression, Iterable, Sequence, CharSequence) into an IndexedValue containing the index of that element and the element
|
||||||
|
// itself. The iterator for this lazy Iterable looks like this:
|
||||||
|
//
|
||||||
|
// internal class IndexingIterator<out T>(private val iterator: Iterator<T>) : Iterator<IndexedValue<T>> {
|
||||||
|
// private var index = 0
|
||||||
|
// override fun hasNext() = iterator.hasNext()
|
||||||
|
// override fun next() = IndexedValue(checkIndexOverflow(index++), iterator.next())
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// IndexedValue looks like this:
|
||||||
|
//
|
||||||
|
// data class IndexedValue<out T>(val index: Int, val value: T)
|
||||||
|
//
|
||||||
|
// For example, if the `for` loop is:
|
||||||
|
//
|
||||||
|
// for ((i, v) in (1..10 step 2).withIndex()) { /* Loop body */ }
|
||||||
|
//
|
||||||
|
// ...the optimized loop for the underlying progression looks something like this:
|
||||||
|
//
|
||||||
|
// var inductionVar = 1
|
||||||
|
// val last = 10
|
||||||
|
// val step = 2
|
||||||
|
// if (inductionVar <= last) {
|
||||||
|
// do {
|
||||||
|
// val v = inductionVar
|
||||||
|
// inductionVar += step
|
||||||
|
// // Loop body
|
||||||
|
// } while (inductionVar <= last)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ...and the optimized loop with `withIndex()` looks something like this (see "// ADDED" statements):
|
||||||
|
//
|
||||||
|
// var inductionVar = 1
|
||||||
|
// val last = 10
|
||||||
|
// val step = 2
|
||||||
|
// var index = 0 // ADDED
|
||||||
|
// if (inductionVar <= last) {
|
||||||
|
// do {
|
||||||
|
// val i = index // ADDED
|
||||||
|
// val v = inductionVar
|
||||||
|
// inductionVar += step
|
||||||
|
// // Loop body
|
||||||
|
// checkIndexOverflow(index++) // ADDED
|
||||||
|
// } while (inductionVar <= last)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We "wire" the 1st destructured component to index, and the 2nd to the loop variable value from the underlying iterable.
|
||||||
|
loopVariableComponents[1]?.initializer = irGet(indexVariable)
|
||||||
|
listOfNotNull(loopVariableComponents[1]) + nestedLoopHeader.initializeIteration(
|
||||||
|
loopVariableComponents[2],
|
||||||
|
linkedMapOf(),
|
||||||
|
symbols,
|
||||||
|
builder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the nested loop header to build the loop. More info in comments in initializeIteration().
|
||||||
|
override fun buildLoop(builder: DeclarationIrBuilder, oldLoop: IrLoop, newBody: IrExpression?) =
|
||||||
|
nestedLoopHeader.buildLoop(builder, oldLoop, newBody).apply {
|
||||||
|
if (ownsIndexVariable) {
|
||||||
|
with(builder) {
|
||||||
|
// Add `index++` to end of the loop.
|
||||||
|
// TODO: MUSTDO: Check for overflow for Iterable and Sequence (call to checkIndexOverflow()).
|
||||||
|
val plusFun = indexVariable.type.getClass()!!.functions.first {
|
||||||
|
it.name == OperatorNameConventions.PLUS &&
|
||||||
|
it.valueParameters.size == 1 &&
|
||||||
|
it.valueParameters[0].type.isInt()
|
||||||
|
}
|
||||||
|
(newLoop.body as IrContainerExpression).statements.add(
|
||||||
|
irSetVar(
|
||||||
|
indexVariable.symbol, irCallOp(
|
||||||
|
plusFun.symbol, plusFun.returnType,
|
||||||
|
irGet(indexVariable),
|
||||||
|
irInt(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the for-loop iterator variable, extract information about the iterable subject
|
* Given the for-loop iterator variable, extract information about the iterable subject
|
||||||
* and create a [ForLoopHeader] from it.
|
* and create a [ForLoopHeader] from it.
|
||||||
@@ -338,7 +501,7 @@ internal class HeaderProcessor(
|
|||||||
*
|
*
|
||||||
* Returns null if the for-loop cannot be lowered.
|
* Returns null if the for-loop cannot be lowered.
|
||||||
*/
|
*/
|
||||||
fun processHeader(variable: IrVariable): ForLoopHeader? {
|
fun extractHeader(variable: IrVariable): ForLoopHeader? {
|
||||||
// Verify the variable type is a subtype of Iterator<*>.
|
// Verify the variable type is a subtype of Iterator<*>.
|
||||||
assert(variable.origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR)
|
assert(variable.origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR)
|
||||||
if (!variable.type.isSubtypeOfClass(symbols.iterator)) {
|
if (!variable.type.isSubtypeOfClass(symbols.iterator)) {
|
||||||
@@ -365,6 +528,7 @@ internal class HeaderProcessor(
|
|||||||
return when (headerInfo) {
|
return when (headerInfo) {
|
||||||
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(headerInfo, builder)
|
is IndexedGetHeaderInfo -> IndexedGetLoopHeader(headerInfo, builder)
|
||||||
is ProgressionHeaderInfo -> ProgressionLoopHeader(headerInfo, builder)
|
is ProgressionHeaderInfo -> ProgressionLoopHeader(headerInfo, builder)
|
||||||
|
is WithIndexHeaderInfo -> WithIndexLoopHeader(headerInfo, builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -695,3 +695,34 @@ internal open class CharSequenceIterationHandler(context: CommonBackendContext,
|
|||||||
internal class StringIterationHandler(context: CommonBackendContext) : CharSequenceIterationHandler(context, canCacheLast = true) {
|
internal class StringIterationHandler(context: CommonBackendContext) : CharSequenceIterationHandler(context, canCacheLast = true) {
|
||||||
override fun matchIterable(expression: IrExpression) = expression.type.isString()
|
override fun matchIterable(expression: IrExpression) = expression.type.isString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Builds a [HeaderInfo] for calls to `withIndex()`. */
|
||||||
|
internal class WithIndexHandler(context: CommonBackendContext, private val visitor: HeaderInfoBuilder) :
|
||||||
|
HeaderInfoFromCallHandler<Nothing?> {
|
||||||
|
|
||||||
|
// Use Quantifier.ANY so we can handle all `withIndex()` calls in the same manner.
|
||||||
|
override val matcher = createIrCallMatcher(Quantifier.ANY) {
|
||||||
|
callee {
|
||||||
|
fqName { it == FqName("kotlin.collections.withIndex") }
|
||||||
|
extensionReceiver { it != null && it.type.run { isArray() || isPrimitiveArray() } }
|
||||||
|
parameterCount { it == 0 }
|
||||||
|
}
|
||||||
|
callee {
|
||||||
|
fqName { it == FqName("kotlin.text.withIndex") }
|
||||||
|
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.charSequence) }
|
||||||
|
parameterCount { it == 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle Iterable.withIndex(), Sequence.withIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo? {
|
||||||
|
// WithIndexHeaderInfo is a composite that contains the HeaderInfo for the underlying iterable (if any).
|
||||||
|
val nestedInfo = expression.extensionReceiver!!.accept(visitor, null) ?: return null
|
||||||
|
|
||||||
|
// We cannot lower `iterable.withIndex().withIndex()`.
|
||||||
|
if (nestedInfo is WithIndexHeaderInfo) return null
|
||||||
|
|
||||||
|
return WithIndexHeaderInfo(nestedInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
val arr = arrayOf("a", "b", "c", "d")
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
for ((_, _) in arr.withIndex()) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (count == 4) "OK" else "fail: '$count'"
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
val arr = arrayOf("a", "b", "c", "d")
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val s = StringBuilder()
|
||||||
|
|
||||||
|
for (iv in arr.withIndex()) {
|
||||||
|
val (i, x) = iv
|
||||||
|
s.append("$i:$x;")
|
||||||
|
}
|
||||||
|
|
||||||
|
val ss = s.toString()
|
||||||
|
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
val xs = "abcd"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
for ((_, _) in xs.withIndex()) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (count == 4) "OK" else "fail: '$count'"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val s = StringBuilder()
|
||||||
|
|
||||||
|
for (iv in "abcd".withIndex()) {
|
||||||
|
val (index, x) = iv
|
||||||
|
s.append("$index:$x;")
|
||||||
|
}
|
||||||
|
|
||||||
|
val ss = s.toString()
|
||||||
|
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
|
||||||
|
}
|
||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val arr = arrayOf("a", "b", "c", "d")
|
val arr = arrayOf("a", "b", "c", "d")
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -19,3 +18,6 @@ fun box(): String {
|
|||||||
// 0 component1
|
// 0 component1
|
||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 ARRAYLENGTH
|
// 1 ARRAYLENGTH
|
||||||
|
|
||||||
|
// The 1st ICONST_0 is for initializing the array. 2nd is for initializing the index in the lowered for-loop.
|
||||||
|
// 2 ICONST_0
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val arr = arrayOf("a", "b", "c", "d")
|
val arr = arrayOf("a", "b", "c", "d")
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -19,3 +18,6 @@ fun box(): String {
|
|||||||
// 0 component1
|
// 0 component1
|
||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 ARRAYLENGTH
|
// 1 ARRAYLENGTH
|
||||||
|
|
||||||
|
// The 1st ICONST_0 is for initializing the array. 2nd is for initializing the index in the lowered for-loop.
|
||||||
|
// 2 ICONST_0
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val arr = intArrayOf()
|
val arr = intArrayOf()
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -16,3 +15,6 @@ fun box(): String {
|
|||||||
// 0 component1
|
// 0 component1
|
||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 ARRAYLENGTH
|
// 1 ARRAYLENGTH
|
||||||
|
|
||||||
|
// The 1st ICONST_0 is for initializing the array. 2nd is for initializing the index in the lowered for-loop.
|
||||||
|
// 2 ICONST_0
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val arr = intArrayOf(10, 20, 30, 40)
|
val arr = intArrayOf(10, 20, 30, 40)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -17,3 +16,6 @@ fun box(): String {
|
|||||||
// 0 component1
|
// 0 component1
|
||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 ARRAYLENGTH
|
// 1 ARRAYLENGTH
|
||||||
|
|
||||||
|
// The 1st ICONST_0 is for initializing the array. 2nd is for initializing the index in the lowered for-loop.
|
||||||
|
// 2 ICONST_0
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val arr = arrayOf("a", "b", "c", "d")
|
val arr = arrayOf("a", "b", "c", "d")
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -19,3 +18,6 @@ fun box(): String {
|
|||||||
// 0 component1
|
// 0 component1
|
||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 ARRAYLENGTH
|
// 1 ARRAYLENGTH
|
||||||
|
|
||||||
|
// The 1st ICONST_0 is for initializing the array. 2nd is for initializing the index in the lowered for-loop.
|
||||||
|
// 2 ICONST_0
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val cs: CharSequence = "abcd"
|
val cs: CharSequence = "abcd"
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -20,3 +19,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
for ((index, x) in "".withIndex()) {
|
for ((index, x) in "".withIndex()) {
|
||||||
return "Loop over empty String should not be executed"
|
return "Loop over empty String should not be executed"
|
||||||
@@ -14,3 +13,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val s = StringBuilder()
|
val s = StringBuilder()
|
||||||
|
|
||||||
@@ -18,3 +17,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -20,3 +19,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
@@ -20,3 +19,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
val xs = "abcd"
|
val xs = "abcd"
|
||||||
|
|
||||||
fun useAny(x: Any) {}
|
fun useAny(x: Any) {}
|
||||||
@@ -23,3 +22,6 @@ fun box(): String {
|
|||||||
// 0 component2
|
// 0 component2
|
||||||
// 1 length
|
// 1 length
|
||||||
// 1 charAt
|
// 1 charAt
|
||||||
|
|
||||||
|
// The ICONST_0 is for initializing the index in the lowered for-loop.
|
||||||
|
// 1 ICONST_0
|
||||||
|
|||||||
+20
@@ -5301,11 +5301,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
@@ -5419,11 +5429,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
+20
@@ -5301,11 +5301,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
@@ -5419,11 +5429,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
+48
-28
@@ -5266,19 +5266,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexContinuesAsUnmodified.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexContinuesAsUnmodified.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrrayWithIndexNoElementVar.kt")
|
@TestMetadata("forInArrayWithIndexNoElementVar.kt")
|
||||||
public void testForInArrrayWithIndexNoElementVar() throws Exception {
|
public void testForInArrayWithIndexNoElementVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
public void testForInArrrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInByteArrayWithIndex.kt")
|
||||||
|
public void testForInByteArrayWithIndex() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInByteArrayWithIndex.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInByteArrayWithIndexWithSmartCast.kt")
|
@TestMetadata("forInByteArrayWithIndexWithSmartCast.kt")
|
||||||
@@ -5286,14 +5301,9 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInByteArrayWithIndexWithSmartCast.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInByteArrayWithIndexWithSmartCast.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInByteArrrayWithIndex.kt")
|
@TestMetadata("forInEmptyArrayWithIndex.kt")
|
||||||
public void testForInByteArrrayWithIndex() throws Exception {
|
public void testForInEmptyArrayWithIndex() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInByteArrrayWithIndex.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInEmptyArrayWithIndex.kt");
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("forInEmptyArrrayWithIndex.kt")
|
|
||||||
public void testForInEmptyArrrayWithIndex() throws Exception {
|
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInEmptyArrrayWithIndex.kt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInGenericArrayOfIntsWithIndex.kt")
|
@TestMetadata("forInGenericArrayOfIntsWithIndex.kt")
|
||||||
@@ -5311,30 +5321,30 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInGenericArrayWithIndex.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInGenericArrayWithIndex.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInIntArrayWithIndex.kt")
|
||||||
|
public void testForInIntArrayWithIndex() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInIntArrayWithIndex.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInIntArrayWithIndexWithSmartCast.kt")
|
@TestMetadata("forInIntArrayWithIndexWithSmartCast.kt")
|
||||||
public void testForInIntArrayWithIndexWithSmartCast() throws Exception {
|
public void testForInIntArrayWithIndexWithSmartCast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInIntArrayWithIndexWithSmartCast.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInIntArrayWithIndexWithSmartCast.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInIntArrrayWithIndex.kt")
|
@TestMetadata("forInObjectArrayWithIndex.kt")
|
||||||
public void testForInIntArrrayWithIndex() throws Exception {
|
public void testForInObjectArrayWithIndex() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInIntArrrayWithIndex.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInObjectArrayWithIndex.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInObjectArrrayWithIndex.kt")
|
@TestMetadata("forInShortArrayWithIndex.kt")
|
||||||
public void testForInObjectArrrayWithIndex() throws Exception {
|
public void testForInShortArrayWithIndex() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInObjectArrrayWithIndex.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInShortArrayWithIndex.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInShortArrayWithIndexWithSmartCast.kt")
|
@TestMetadata("forInShortArrayWithIndexWithSmartCast.kt")
|
||||||
public void testForInShortArrayWithIndexWithSmartCast() throws Exception {
|
public void testForInShortArrayWithIndexWithSmartCast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInShortArrayWithIndexWithSmartCast.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInShortArrayWithIndexWithSmartCast.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("forInShortArrrayWithIndex.kt")
|
|
||||||
public void testForInShortArrrayWithIndex() throws Exception {
|
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInShortArrrayWithIndex.kt");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex")
|
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex")
|
||||||
@@ -5389,11 +5399,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
+20
@@ -5271,11 +5271,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
@@ -5389,11 +5399,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
Generated
+20
@@ -4401,11 +4401,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
@@ -4519,11 +4529,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
+20
@@ -4411,11 +4411,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInArrayWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
@TestMetadata("forInArrayWithIndexNoIndexVar.kt")
|
||||||
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
public void testForInArrayWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInArrayWithIndexNotDestructured.kt")
|
||||||
|
public void testForInArrayWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInArrayWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
@@ -4529,11 +4539,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoElementVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNoIndexOrElementVar.kt")
|
||||||
|
public void testForInStringWithIndexNoIndexOrElementVar() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexOrElementVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
@TestMetadata("forInStringWithIndexNoIndexVar.kt")
|
||||||
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
public void testForInStringWithIndexNoIndexVar() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNoIndexVar.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInStringWithIndexNotDestructured.kt")
|
||||||
|
public void testForInStringWithIndexNotDestructured() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexNotDestructured.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
@TestMetadata("forInStringWithIndexWithExplicitlyTypedIndexVariable.kt")
|
||||||
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
public void testForInStringWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
runTest("compiler/testData/codegen/box/controlStructures/forInCharSequenceWithIndex/forInStringWithIndexWithExplicitlyTypedIndexVariable.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user