Add DefaultProgressionHandler that handles for-loops over

non-specialized progressions, including "step" progressions.

DefaultProgressionHandler uses the "first/last/step" properties of
the progression when building the loop header.
This commit is contained in:
Mark Punzalan
2019-03-20 00:01:32 -07:00
committed by max-kammerer
parent 301ac90770
commit ea9572ad28
9 changed files with 56 additions and 10 deletions
@@ -134,12 +134,20 @@ private class ProgressionHeaderInfoBuilder(val context: CommonBackendContext) :
}
internal class HeaderInfoBuilder(context: CommonBackendContext) {
private val progressionInfoBuilder = ProgressionHeaderInfoBuilder(context)
private val progressionHeaderInfoBuilder = ProgressionHeaderInfoBuilder(context)
private val arrayIterationHandler = ArrayIterationHandler(context)
private val defaultProgressionHandler = DefaultProgressionHandler(context)
fun build(variable: IrVariable): HeaderInfo? {
val initializer = variable.initializer!! as IrCall
// TODO: Merge DefaultProgressionHandler into ProgressionHeaderInfoBuilder. Not
// straightforward because ProgressionHeaderInfoBuilder works only on calls and not just
// any progression expression (i.e., progression may not be a call result).
// DefaultProgressionHandler must come AFTER ProgressionHeaderInfoBuilder, which handles
// more specialized forms of progressions.
val initializer = variable.initializer as IrCall
return arrayIterationHandler.handle(initializer, null)
?: initializer.dispatchReceiver?.accept(progressionInfoBuilder, null)
?: initializer.dispatchReceiver?.accept(progressionHeaderInfoBuilder, null)
?: defaultProgressionHandler.handle(initializer, null)
}
}
@@ -161,6 +161,44 @@ internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHa
}
}
/** Builds a [HeaderInfo] for progressions not handled by more specialized handlers. */
internal class DefaultProgressionHandler(private val context: CommonBackendContext) : HeaderInfoHandler<Nothing?> {
private val symbols = context.ir.symbols
override val matcher = createIrCallMatcher {
origin { it == IrStatementOrigin.FOR_LOOP_ITERATOR }
dispatchReceiver { it != null && ProgressionType.fromIrType(it.type, symbols) != null }
}
override fun build(call: IrCall, progressionType: Nothing?): HeaderInfo? =
with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
// Directly use the `first/last/step` properties of the progression.
val progression = scope.createTemporaryVariable(call.dispatchReceiver!!)
val progressionClass = progression.type.getClass()!!
val firstProperty = progressionClass.properties.first { it.name.asString() == "first" }
val first = irCall(firstProperty.getter!!).apply {
dispatchReceiver = irGet(progression)
}
val lastProperty = progressionClass.properties.first { it.name.asString() == "last" }
val last = irCall(lastProperty.getter!!).apply {
dispatchReceiver = irGet(progression)
}
val stepProperty = progressionClass.properties.first { it.name.asString() == "step" }
val step = irCall(stepProperty.getter!!).apply {
dispatchReceiver = irGet(progression)
}
ProgressionHeaderInfo(
ProgressionType.fromIrType(progression.type, symbols)!!,
first,
last,
step,
additionalVariables = listOf(progression)
)
}
}
internal class ArrayIterationHandler(private val context: CommonBackendContext) : HeaderInfoHandler<Nothing?> {
private val intDecFun = ProgressionType.INT_PROGRESSION.decFun(context.irBuiltIns)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
import kotlin.test.assertEquals
fun test(coll: Collection<*>?): Int {
@@ -11,3 +11,4 @@ fun Int.digitsUpto(end: Int): Int {
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getStep
@@ -7,4 +7,5 @@ fun f() {
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getLast
// 0 getStep
@@ -7,4 +7,5 @@ fun f(a: Int, b: Int) {
// 0 getStart
// 0 getEnd
// 0 getFirst
// 0 getLast
// 0 getLast
// 0 getStep
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun f() {
for (i in 0..5 step 2) {
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun f(r: IntRange) {
for (i in r) {
}
@@ -8,4 +7,5 @@ fun f(r: IntRange) {
// 0 getStart
// 0 getEnd
// 1 getFirst
// 1 getLast
// 1 getLast
// 1 getStep
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun Int.until(other: Int) = this..other - 1
fun foo() {
val range = 1 until 2