Make HeaderInfo.step not nullable and have handlers explicitly provide

the step expression.

The semantics of "step" are now clearer: It will no longer be negated
based on the "increasing" property; if the progression is decreasing
(i.e., for "downTo" progressions), then it must be negative. The
"increasing" property is still used when building the emptiness
condition.
This commit is contained in:
Mark Punzalan
2019-03-19 16:51:26 -07:00
committed by max-kammerer
parent 40dbf8a3fd
commit ed9ede8936
3 changed files with 65 additions and 60 deletions
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.matchers.IrCallMatcher
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -52,7 +51,7 @@ internal sealed class HeaderInfo(
val progressionType: ProgressionType,
val lowerBound: IrExpression,
val upperBound: IrExpression,
val step: IrExpression?, // null value denotes default step (1)
val step: IrExpression,
val increasing: Boolean,
val closed: Boolean
)
@@ -61,7 +60,7 @@ internal class ProgressionHeaderInfo(
progressionType: ProgressionType,
lowerBound: IrExpression,
upperBound: IrExpression,
step: IrExpression? = null,
step: IrExpression,
increasing: Boolean = true,
closed: Boolean = true
) : HeaderInfo(progressionType, lowerBound, upperBound, step, increasing, closed)
@@ -69,12 +68,13 @@ internal class ProgressionHeaderInfo(
internal class ArrayHeaderInfo(
lowerBound: IrExpression,
upperBound: IrExpression,
val arrayDeclaration: IrValueDeclaration
step: IrExpression,
val arrayVariable: IrVariable
) : HeaderInfo(
ProgressionType.INT_PROGRESSION,
lowerBound,
upperBound,
step = null,
step,
increasing = true,
closed = false
)
@@ -102,9 +102,9 @@ private class ProgressionHeaderInfoBuilder(val context: CommonBackendContext) :
private val progressionHandlers = listOf(
IndicesHandler(context),
UntilHandler(progressionElementTypes),
DownToHandler(progressionElementTypes),
RangeToHandler(progressionElementTypes)
UntilHandler(context, progressionElementTypes),
DownToHandler(context, progressionElementTypes),
RangeToHandler(context, progressionElementTypes)
)
override fun visitElement(element: IrElement, data: Nothing?): HeaderInfo? = null
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrWhileLoopImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -93,7 +92,7 @@ internal class ArrayLoopHeader(
step: IrVariable
) : ForLoopHeader(inductionVariable, bound, last, step, ProgressionType.INT_PROGRESSION) {
private val arrayDeclaration = headerInfo.arrayDeclaration
private val arrayDeclaration = headerInfo.arrayVariable
override fun initializeLoopVariable(symbols: Symbols<CommonBackendContext>, builder: DeclarationIrBuilder) = with(builder) {
val arrayClass = (arrayDeclaration.type.classifierOrNull) as IrClassSymbol
@@ -143,7 +142,7 @@ internal class HeaderProcessor(
val progressionInfo = headerInfoBuilder.build(variable)
?: return null
if (progressionInfo is ArrayHeaderInfo) {
progressionInfo.arrayDeclaration.parent = variable.parent
progressionInfo.arrayVariable.parent = variable.parent
}
with(builder) {
with(progressionInfo) {
@@ -168,11 +167,7 @@ internal class HeaderProcessor(
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
)
val stepExpression = if (step != null) {
ensureNotNullable(if (increasing) step else step.unaryMinus())
} else {
defaultStep(startOffset, endOffset)
}
val stepExpression = ensureNotNullable(step)
val stepValue = scope.createTemporaryVariable(
stepExpression,
@@ -237,23 +232,4 @@ internal class HeaderProcessor(
} else {
expression
}
private fun IrExpression.unaryMinus(): IrExpression {
val unaryOperator = symbols.getUnaryOperator(OperatorNameConventions.UNARY_MINUS, type.toKotlinType())
return IrCallImpl(startOffset, endOffset, unaryOperator.owner.returnType, unaryOperator).apply {
dispatchReceiver = this@unaryMinus
}
}
private fun HeaderInfo.defaultStep(startOffset: Int, endOffset: Int): IrExpression {
val type = progressionType.elementType(context.irBuiltIns)
val step = if (increasing) 1 else -1
return when {
type.isInt() || type.isChar() ->
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, step)
type.isLong() ->
IrConstImpl.long(startOffset, endOffset, context.irBuiltIns.longType, step.toLong())
else -> throw IllegalArgumentException()
}
}
}
@@ -14,16 +14,19 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.properties
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.SimpleType
// TODO: What if functions like Int.rangeTo(Char) will be added to stdlib later?
internal class RangeToHandler(val progressionElementTypes: Collection<SimpleType>) : ProgressionHandler {
internal class RangeToHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<SimpleType>) :
ProgressionHandler {
override val matcher = SimpleCalleeMatcher {
dispatchReceiver { it != null && it.type.toKotlinType() in progressionElementTypes }
fqName { it.pathSegments().last() == Name.identifier("rangeTo") }
@@ -32,49 +35,64 @@ internal class RangeToHandler(val progressionElementTypes: Collection<SimpleType
}
override fun build(call: IrCall, data: ProgressionType) =
ProgressionHeaderInfo(data, call.dispatchReceiver!!, call.getValueArgument(0)!!)
with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
ProgressionHeaderInfo(
data,
lowerBound = call.dispatchReceiver!!,
upperBound = call.getValueArgument(0)!!,
step = irInt(1)
)
}
}
internal class DownToHandler(val progressionElementTypes: Collection<SimpleType>) : ProgressionHandler {
internal class DownToHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<SimpleType>) :
ProgressionHandler {
override val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type.toKotlinType() in progressionElementTypes }
}
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
ProgressionHeaderInfo(
data,
call.extensionReceiver!!,
call.getValueArgument(0)!!,
increasing = false
)
with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
ProgressionHeaderInfo(
data,
lowerBound = call.extensionReceiver!!,
upperBound = call.getValueArgument(0)!!,
step = irInt(-1),
increasing = false
)
}
}
internal class UntilHandler(val progressionElementTypes: Collection<SimpleType>) : ProgressionHandler {
internal class UntilHandler(private val context: CommonBackendContext, private val progressionElementTypes: Collection<SimpleType>) :
ProgressionHandler {
override val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type.toKotlinType() in progressionElementTypes }
}
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
ProgressionHeaderInfo(
data,
call.extensionReceiver!!,
call.getValueArgument(0)!!,
closed = false
)
with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
ProgressionHeaderInfo(
data,
lowerBound = call.extensionReceiver!!,
upperBound = call.getValueArgument(0)!!,
step = irInt(1),
closed = false
)
}
}
internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHandler {
override val matcher = createIrCallMatcher {
callee {
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
override val matcher = SimpleCalleeMatcher {
// TODO: Handle Collection<*>.indices
// TODO: Handle CharSequence.indices
extensionReceiver { it != null && KotlinBuiltIns.isArrayOrPrimitiveArray(it.type.toKotlinType()) }
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
@@ -85,7 +103,13 @@ internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHa
val upperBound = irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = call.extensionReceiver
}
ProgressionHeaderInfo(data, lowerBound, upperBound, closed = false)
ProgressionHeaderInfo(
data,
lowerBound,
upperBound,
step = irInt(1),
closed = false
)
}
}
@@ -114,6 +138,11 @@ internal class ArrayIterationHandler(val context: CommonBackendContext) : Header
val upperBound = irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = irGet(arrayReference)
}
ArrayHeaderInfo(irInt(0), upperBound, arrayReference)
ArrayHeaderInfo(
lowerBound = irInt(0),
upperBound = upperBound,
step = irInt(1),
arrayVariable = arrayReference
)
}
}