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.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.matchers.IrCallMatcher import org.jetbrains.kotlin.backend.common.lower.matchers.IrCallMatcher
import org.jetbrains.kotlin.ir.IrElement 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.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -52,7 +51,7 @@ internal sealed class HeaderInfo(
val progressionType: ProgressionType, val progressionType: ProgressionType,
val lowerBound: IrExpression, val lowerBound: IrExpression,
val upperBound: IrExpression, val upperBound: IrExpression,
val step: IrExpression?, // null value denotes default step (1) val step: IrExpression,
val increasing: Boolean, val increasing: Boolean,
val closed: Boolean val closed: Boolean
) )
@@ -61,7 +60,7 @@ internal class ProgressionHeaderInfo(
progressionType: ProgressionType, progressionType: ProgressionType,
lowerBound: IrExpression, lowerBound: IrExpression,
upperBound: IrExpression, upperBound: IrExpression,
step: IrExpression? = null, step: IrExpression,
increasing: Boolean = true, increasing: Boolean = true,
closed: Boolean = true closed: Boolean = true
) : HeaderInfo(progressionType, lowerBound, upperBound, step, increasing, closed) ) : HeaderInfo(progressionType, lowerBound, upperBound, step, increasing, closed)
@@ -69,12 +68,13 @@ internal class ProgressionHeaderInfo(
internal class ArrayHeaderInfo( internal class ArrayHeaderInfo(
lowerBound: IrExpression, lowerBound: IrExpression,
upperBound: IrExpression, upperBound: IrExpression,
val arrayDeclaration: IrValueDeclaration step: IrExpression,
val arrayVariable: IrVariable
) : HeaderInfo( ) : HeaderInfo(
ProgressionType.INT_PROGRESSION, ProgressionType.INT_PROGRESSION,
lowerBound, lowerBound,
upperBound, upperBound,
step = null, step,
increasing = true, increasing = true,
closed = false closed = false
) )
@@ -102,9 +102,9 @@ private class ProgressionHeaderInfoBuilder(val context: CommonBackendContext) :
private val progressionHandlers = listOf( private val progressionHandlers = listOf(
IndicesHandler(context), IndicesHandler(context),
UntilHandler(progressionElementTypes), UntilHandler(context, progressionElementTypes),
DownToHandler(progressionElementTypes), DownToHandler(context, progressionElementTypes),
RangeToHandler(progressionElementTypes) RangeToHandler(context, progressionElementTypes)
) )
override fun visitElement(element: IrElement, data: Nothing?): HeaderInfo? = null 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.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl 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.IrDoWhileLoopImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrWhileLoopImpl import org.jetbrains.kotlin.ir.expressions.impl.IrWhileLoopImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -93,7 +92,7 @@ internal class ArrayLoopHeader(
step: IrVariable step: IrVariable
) : ForLoopHeader(inductionVariable, bound, last, step, ProgressionType.INT_PROGRESSION) { ) : 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) { override fun initializeLoopVariable(symbols: Symbols<CommonBackendContext>, builder: DeclarationIrBuilder) = with(builder) {
val arrayClass = (arrayDeclaration.type.classifierOrNull) as IrClassSymbol val arrayClass = (arrayDeclaration.type.classifierOrNull) as IrClassSymbol
@@ -143,7 +142,7 @@ internal class HeaderProcessor(
val progressionInfo = headerInfoBuilder.build(variable) val progressionInfo = headerInfoBuilder.build(variable)
?: return null ?: return null
if (progressionInfo is ArrayHeaderInfo) { if (progressionInfo is ArrayHeaderInfo) {
progressionInfo.arrayDeclaration.parent = variable.parent progressionInfo.arrayVariable.parent = variable.parent
} }
with(builder) { with(builder) {
with(progressionInfo) { with(progressionInfo) {
@@ -168,11 +167,7 @@ internal class HeaderProcessor(
origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE
) )
val stepExpression = if (step != null) { val stepExpression = ensureNotNullable(step)
ensureNotNullable(if (increasing) step else step.unaryMinus())
} else {
defaultStep(startOffset, endOffset)
}
val stepValue = scope.createTemporaryVariable( val stepValue = scope.createTemporaryVariable(
stepExpression, stepExpression,
@@ -237,23 +232,4 @@ internal class HeaderProcessor(
} else { } else {
expression 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.irCall
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irInt 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.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.ir.util.properties
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
// TODO: What if functions like Int.rangeTo(Char) will be added to stdlib later? // 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 { override val matcher = SimpleCalleeMatcher {
dispatchReceiver { it != null && it.type.toKotlinType() in progressionElementTypes } dispatchReceiver { it != null && it.type.toKotlinType() in progressionElementTypes }
fqName { it.pathSegments().last() == Name.identifier("rangeTo") } 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) = 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 { override val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes) singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type.toKotlinType() in progressionElementTypes } parameter(0) { it.type.toKotlinType() in progressionElementTypes }
} }
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? = override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
ProgressionHeaderInfo( with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
data, ProgressionHeaderInfo(
call.extensionReceiver!!, data,
call.getValueArgument(0)!!, lowerBound = call.extensionReceiver!!,
increasing = false 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 { override val matcher = SimpleCalleeMatcher {
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes) singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
parameterCount { it == 1 }
parameter(0) { it.type.toKotlinType() in progressionElementTypes } parameter(0) { it.type.toKotlinType() in progressionElementTypes }
} }
override fun build(call: IrCall, data: ProgressionType): HeaderInfo? = override fun build(call: IrCall, data: ProgressionType): HeaderInfo? =
ProgressionHeaderInfo( with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) {
data, ProgressionHeaderInfo(
call.extensionReceiver!!, data,
call.getValueArgument(0)!!, lowerBound = call.extensionReceiver!!,
closed = false upperBound = call.getValueArgument(0)!!,
) step = irInt(1),
closed = false
)
}
} }
internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHandler { internal class IndicesHandler(val context: CommonBackendContext) : ProgressionHandler {
override val matcher = createIrCallMatcher { override val matcher = SimpleCalleeMatcher {
callee {
fqName { it == FqName("kotlin.collections.<get-indices>") }
parameterCount { it == 0 }
}
// TODO: Handle Collection<*>.indices // TODO: Handle Collection<*>.indices
// TODO: Handle CharSequence.indices // TODO: Handle CharSequence.indices
extensionReceiver { it != null && KotlinBuiltIns.isArrayOrPrimitiveArray(it.type.toKotlinType()) } 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? = 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 { val upperBound = irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = call.extensionReceiver 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 { val upperBound = irCall(arraySizeProperty.getter!!).apply {
dispatchReceiver = irGet(arrayReference) dispatchReceiver = irGet(arrayReference)
} }
ArrayHeaderInfo(irInt(0), upperBound, arrayReference) ArrayHeaderInfo(
lowerBound = irInt(0),
upperBound = upperBound,
step = irInt(1),
arrayVariable = arrayReference
)
} }
} }