IR: remove IrCallMatcher/IrFunctionMatcher and usages
There doesn't seem to be much value over a simple imperative code which checks exactly the same things in the same order. The main downside of the removed API is that it was more difficult to debug.
This commit is contained in:
+18
-25
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
@@ -29,10 +28,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
|
||||||
import org.jetbrains.kotlin.ir.util.shallowCopy
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -60,14 +56,14 @@ private class Transformer(
|
|||||||
val context: CommonBackendContext,
|
val context: CommonBackendContext,
|
||||||
val container: IrSymbolOwner
|
val container: IrSymbolOwner
|
||||||
) : IrElementTransformerVoidWithContext() {
|
) : IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
private val headerInfoBuilder = RangeHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
private val headerInfoBuilder = RangeHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
||||||
fun getScopeOwnerSymbol() = currentScope?.scope?.scopeOwnerSymbol ?: container.symbol
|
fun getScopeOwnerSymbol() = currentScope?.scope?.scopeOwnerSymbol ?: container.symbol
|
||||||
|
|
||||||
val stdlibExtensionContainsCallMatcher = SimpleCalleeMatcher {
|
private fun matchStdlibExtensionContainsCall(expression: IrCall): Boolean {
|
||||||
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.closedRange) }
|
val callee = expression.symbol.owner
|
||||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.CONTAINS}") }
|
return callee.valueParameters.size == 1 &&
|
||||||
parameterCount { it == 1 }
|
callee.extensionReceiverParameter?.type?.isSubtypeOfClass(context.ir.symbols.closedRange) == true &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.ranges.${OperatorNameConventions.CONTAINS}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
@@ -89,7 +85,7 @@ private class Transformer(
|
|||||||
return super.visitCall(expression) // Preserve the call to not().
|
return super.visitCall(expression) // Preserve the call to not().
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression.extensionReceiver != null && !stdlibExtensionContainsCallMatcher(expression)) {
|
if (expression.extensionReceiver != null && !matchStdlibExtensionContainsCall(expression)) {
|
||||||
// We can only optimize calls to the stdlib extension functions and not a user-defined extension.
|
// We can only optimize calls to the stdlib extension functions and not a user-defined extension.
|
||||||
// TODO: This breaks the optimization for *Range.reversed().contains(). The function called there is the extension function
|
// TODO: This breaks the optimization for *Range.reversed().contains(). The function called there is the extension function
|
||||||
// Iterable.contains(). Figure out if we can safely match on that as well.
|
// Iterable.contains(). Figure out if we can safely match on that as well.
|
||||||
@@ -412,15 +408,13 @@ internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeO
|
|||||||
|
|
||||||
/** Builds a [HeaderInfo] for closed floating-point ranges built using the `rangeTo` function. */
|
/** Builds a [HeaderInfo] for closed floating-point ranges built using the `rangeTo` function. */
|
||||||
internal object FloatingPointRangeToHandler : HeaderInfoHandler<IrCall, Nothing?> {
|
internal object FloatingPointRangeToHandler : HeaderInfoHandler<IrCall, Nothing?> {
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
|
val callee = expression.symbol.owner
|
||||||
extensionReceiver { it != null && it.type.run { isFloat() || isDouble() } }
|
return callee.valueParameters.singleOrNull()?.type?.let { it.isFloat() || it.isDouble() } == true &&
|
||||||
parameterCount { it == 1 }
|
callee.extensionReceiverParameter?.type?.let { it.isFloat() || it.isDouble() } == true &&
|
||||||
parameter(0) { it.type.run { isFloat() || isDouble() } }
|
callee.kotlinFqName == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
||||||
FloatingPointRangeHeaderInfo(
|
FloatingPointRangeHeaderInfo(
|
||||||
start = expression.extensionReceiver!!,
|
start = expression.extensionReceiver!!,
|
||||||
@@ -429,15 +423,14 @@ internal object FloatingPointRangeToHandler : HeaderInfoHandler<IrCall, Nothing?
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for ranges of Comparables built using the `rangeTo` extension function. */
|
/** Builds a [HeaderInfo] for ranges of Comparables built using the `rangeTo` extension function. */
|
||||||
internal class ComparableRangeToHandler(context: CommonBackendContext) : HeaderInfoHandler<IrCall, Nothing?> {
|
internal class ComparableRangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, Nothing?> {
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
|
val callee = expression.symbol.owner
|
||||||
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.comparable) }
|
return callee.valueParameters.size == 1 &&
|
||||||
parameterCount { it == 1 }
|
callee.extensionReceiverParameter?.type?.isSubtypeOfClass(context.ir.symbols.comparable) == true &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
||||||
ComparableRangeInfo(
|
ComparableRangeInfo(
|
||||||
start = expression.extensionReceiver!!,
|
start = expression.extensionReceiver!!,
|
||||||
|
|||||||
+15
-14
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.common.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
@@ -15,6 +14,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.types.isString
|
import org.jetbrains.kotlin.ir.types.isString
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
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
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -26,8 +26,8 @@ class StringTrimLowering(val context: CommonBackendContext) : FileLoweringPass,
|
|||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
return when {
|
return when {
|
||||||
trimIndentMatcher(expression) -> maybeComputeTrimIndent(expression)
|
matchTrimIndent(expression) -> maybeComputeTrimIndent(expression)
|
||||||
trimMarginMatcher(expression) -> maybeComputeTrimMargin(expression)
|
matchTrimMargin(expression) -> maybeComputeTrimMargin(expression)
|
||||||
else -> super.visitCall(expression)
|
else -> super.visitCall(expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,20 +64,21 @@ class StringTrimLowering(val context: CommonBackendContext) : FileLoweringPass,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val trimIndentMatcher = SimpleCalleeMatcher {
|
private fun matchTrimIndent(expression: IrCall): Boolean {
|
||||||
extensionReceiver { it != null && it.type.isString() }
|
val callee = expression.symbol.owner
|
||||||
fqName { it == TRIM_INDENT_FQ_NAME }
|
return callee.valueParameters.isEmpty() &&
|
||||||
parameterCount { it == 0 }
|
callee.extensionReceiverParameter?.type?.isString() == true &&
|
||||||
|
callee.kotlinFqName == TRIM_INDENT_FQ_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
private val trimMarginMatcher = SimpleCalleeMatcher {
|
private fun matchTrimMargin(expression: IrCall): Boolean {
|
||||||
extensionReceiver { it != null && it.type.isString() }
|
val callee = expression.symbol.owner
|
||||||
fqName { it == TRIM_MARGIN_FQ_NAME }
|
return callee.valueParameters.singleOrNull()?.type?.isString() == true &&
|
||||||
parameterCount { it == 1 }
|
callee.extensionReceiverParameter?.type?.isString() == true &&
|
||||||
parameter(0) { it.type.isString() }
|
callee.kotlinFqName == TRIM_MARGIN_FQ_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
private val TRIM_MARGIN_FQ_NAME = FqName.fromSegments(listOf("kotlin", "text", "trimMargin"))
|
private val TRIM_MARGIN_FQ_NAME = FqName("kotlin.text.trimMargin")
|
||||||
private val TRIM_INDENT_FQ_NAME = FqName.fromSegments(listOf("kotlin", "text", "trimIndent"))
|
private val TRIM_INDENT_FQ_NAME = FqName("kotlin.text.trimIndent")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.common.lower.loops
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
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.loops.handlers.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.handlers.*
|
||||||
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.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
@@ -242,14 +241,13 @@ internal interface HeaderInfoHandler<E : IrExpression, D> {
|
|||||||
* Matches the `iterator()` call that produced the iterable; if the call matches (or the matcher is null),
|
* Matches the `iterator()` call that produced the iterable; if the call matches (or the matcher is null),
|
||||||
* the handler can build a [HeaderInfo] from the iterable.
|
* the handler can build a [HeaderInfo] from the iterable.
|
||||||
*/
|
*/
|
||||||
val iteratorCallMatcher: IrCallMatcher?
|
fun matchIteratorCall(call: IrCall): Boolean = true
|
||||||
get() = null
|
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] from the expression. */
|
/** Builds a [HeaderInfo] from the expression. */
|
||||||
fun build(expression: E, data: D, scopeOwner: IrSymbol): HeaderInfo?
|
fun build(expression: E, data: D, scopeOwner: IrSymbol): HeaderInfo?
|
||||||
|
|
||||||
fun handle(expression: E, iteratorCall: IrCall?, data: D, scopeOwner: IrSymbol) =
|
fun handle(expression: E, iteratorCall: IrCall?, data: D, scopeOwner: IrSymbol): HeaderInfo? =
|
||||||
if ((iteratorCall == null || iteratorCallMatcher == null || iteratorCallMatcher!!(iteratorCall)) && matchIterable(expression)) {
|
if ((iteratorCall == null || matchIteratorCall(iteratorCall)) && matchIterable(expression)) {
|
||||||
build(expression, data, scopeOwner)
|
build(expression, data, scopeOwner)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|||||||
+2
-1
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
|||||||
internal class DefaultIterableHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
|
internal class DefaultIterableHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
|
||||||
private val iterableClassSymbol = context.ir.symbols.iterable
|
private val iterableClassSymbol = context.ir.symbols.iterable
|
||||||
|
|
||||||
override fun matchIterable(expression: IrExpression) = expression.type.isSubtypeOfClass(iterableClassSymbol)
|
override fun matchIterable(expression: IrExpression): Boolean =
|
||||||
|
expression.type.isSubtypeOfClass(iterableClassSymbol)
|
||||||
|
|
||||||
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
|
|||||||
+2
-5
@@ -24,11 +24,8 @@ internal class DefaultProgressionHandler(
|
|||||||
private val symbols = context.ir.symbols
|
private val symbols = context.ir.symbols
|
||||||
private val rangeClassesTypes = symbols.rangeClasses.map { it.defaultType }.toSet()
|
private val rangeClassesTypes = symbols.rangeClasses.map { it.defaultType }.toSet()
|
||||||
|
|
||||||
override fun matchIterable(expression: IrExpression) = ProgressionType.fromIrType(
|
override fun matchIterable(expression: IrExpression): Boolean =
|
||||||
expression.type,
|
ProgressionType.fromIrType(expression.type, symbols, allowUnsignedBounds) != null
|
||||||
symbols,
|
|
||||||
allowUnsignedBounds
|
|
||||||
) != null
|
|
||||||
|
|
||||||
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
|||||||
internal class DefaultSequenceHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
|
internal class DefaultSequenceHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
|
||||||
private val sequenceClassSymbol = context.ir.symbols.sequence
|
private val sequenceClassSymbol = context.ir.symbols.sequence
|
||||||
|
|
||||||
override fun matchIterable(expression: IrExpression) =
|
override fun matchIterable(expression: IrExpression): Boolean =
|
||||||
sequenceClassSymbol != null && expression.type.isSubtypeOfClass(sequenceClassSymbol)
|
sequenceClassSymbol != null && expression.type.isSubtypeOfClass(sequenceClassSymbol)
|
||||||
|
|
||||||
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
||||||
|
|||||||
+6
-9
@@ -8,8 +8,6 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.singleArgumentExtension
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irInt
|
import org.jetbrains.kotlin.ir.builders.irInt
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
@@ -17,22 +15,21 @@ import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for progressions built using the `downTo` extension function. */
|
/** Builds a [HeaderInfo] for progressions built using the `downTo` extension function. */
|
||||||
internal class DownToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
internal class DownToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||||
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
||||||
|
|
||||||
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||||
|
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
|
val callee = expression.symbol.owner
|
||||||
parameterCount { it == 1 }
|
return callee.valueParameters.singleOrNull()?.type in progressionElementTypes &&
|
||||||
parameter(0) { it.type in progressionElementTypes }
|
callee.extensionReceiverParameter?.type in progressionElementTypes &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.ranges.downTo")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
|
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
val first = expression.extensionReceiver!!
|
val first = expression.extensionReceiver!!
|
||||||
|
|||||||
+20
-26
@@ -10,9 +10,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
|
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.IndexedGetHeaderInfo
|
import org.jetbrains.kotlin.backend.common.lower.loops.IndexedGetHeaderInfo
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.createIrCallMatcher
|
|
||||||
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
import org.jetbrains.kotlin.ir.builders.createTmpVariable
|
||||||
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
|
||||||
@@ -77,22 +74,14 @@ abstract class IndexedGetIterationHandler(
|
|||||||
internal class ArrayIterationHandler(context: CommonBackendContext) : IndexedGetIterationHandler(context, canCacheLast = true) {
|
internal class ArrayIterationHandler(context: CommonBackendContext) : IndexedGetIterationHandler(context, canCacheLast = true) {
|
||||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||||
|
|
||||||
override fun matchIterable(expression: IrExpression) =
|
override fun matchIterable(expression: IrExpression): Boolean {
|
||||||
expression.type.run { isArrayType() } ||
|
if (expression.type.isArrayType()) return true
|
||||||
expression.run {
|
|
||||||
this is IrCall && reversedArrayMatcher(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val reversedArrayMatcher =
|
val callee = (expression as? IrCall)?.symbol?.owner ?: return false
|
||||||
createIrCallMatcher(Quantifier.ANY) {
|
return callee.valueParameters.isEmpty() &&
|
||||||
callee {
|
callee.extensionReceiverParameter?.type?.let { it.isArray() || it.isPrimitiveArray() } == true &&
|
||||||
fqName { it == FqName("kotlin.collections.reversed") }
|
callee.kotlinFqName == FqName("kotlin.collections.reversed")
|
||||||
extensionReceiver {
|
}
|
||||||
it != null && it.type.run { isArray() || isPrimitiveArray() }
|
|
||||||
}
|
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter
|
override val IrType.sizePropertyGetter
|
||||||
get() = getClass()!!.getPropertyGetter("size")!!.owner
|
get() = getClass()!!.getPropertyGetter("size")!!.owner
|
||||||
@@ -123,17 +112,21 @@ internal class ArrayIterationHandler(context: CommonBackendContext) : IndexedGet
|
|||||||
* Note: The value for "last" can NOT be cached (i.e., stored in a variable) because the size/length can change within the loop. This means
|
* Note: The value for "last" can NOT be cached (i.e., stored in a variable) because the size/length can change within the loop. This means
|
||||||
* that "last" is re-evaluated with each iteration of the loop.
|
* that "last" is re-evaluated with each iteration of the loop.
|
||||||
*/
|
*/
|
||||||
internal open class CharSequenceIterationHandler(context: CommonBackendContext, canCacheLast: Boolean = false) :
|
internal open class CharSequenceIterationHandler(
|
||||||
IndexedGetIterationHandler(context, canCacheLast) {
|
context: CommonBackendContext,
|
||||||
override fun matchIterable(expression: IrExpression) = expression.type.isSubtypeOfClass(context.ir.symbols.charSequence)
|
canCacheLast: Boolean = false
|
||||||
|
) : IndexedGetIterationHandler(context, canCacheLast) {
|
||||||
|
override fun matchIterable(expression: IrExpression): Boolean =
|
||||||
|
expression.type.isSubtypeOfClass(context.ir.symbols.charSequence)
|
||||||
|
|
||||||
// We only want to handle the known extension function for CharSequence in the standard library (top level `kotlin.text.iterator`).
|
// We only want to handle the known extension function for CharSequence in the standard library (top level `kotlin.text.iterator`).
|
||||||
// The behavior of this iterator is well-defined and can be lowered. CharSequences can have their own iterators, either as a member or
|
// The behavior of this iterator is well-defined and can be lowered. CharSequences can have their own iterators, either as a member or
|
||||||
// extension function, and the behavior of those custom iterators is unknown.
|
// extension function, and the behavior of those custom iterators is unknown.
|
||||||
override val iteratorCallMatcher = SimpleCalleeMatcher {
|
override fun matchIteratorCall(call: IrCall): Boolean {
|
||||||
extensionReceiver { it != null && it.type.run { isCharSequence() } }
|
val callee = call.symbol.owner
|
||||||
fqName { it == FqName("kotlin.text.${OperatorNameConventions.ITERATOR}") }
|
return callee.valueParameters.isEmpty() &&
|
||||||
parameterCount { it == 0 }
|
callee.extensionReceiverParameter?.type?.isCharSequence() == true &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.text.${OperatorNameConventions.ITERATOR}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||||
@@ -149,7 +142,8 @@ internal open class CharSequenceIterationHandler(context: CommonBackendContext,
|
|||||||
* Note: The value for "last" CAN be cached for Strings as they are immutable and the size/length cannot change.
|
* Note: The value for "last" CAN be cached for Strings as they are immutable and the size/length cannot change.
|
||||||
*/
|
*/
|
||||||
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): Boolean =
|
||||||
|
expression.type.isString()
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||||
get() = context.ir.symbols.string.getPropertyGetter("length")!!.owner
|
get() = context.ir.symbols.string.getPropertyGetter("length")!!.owner
|
||||||
|
|||||||
+18
-23
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irCall
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
import org.jetbrains.kotlin.ir.builders.irInt
|
import org.jetbrains.kotlin.ir.builders.irInt
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
@@ -19,6 +18,7 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
import org.jetbrains.kotlin.ir.util.getPropertyGetter
|
||||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||||
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for progressions built using the `indices` extension property. */
|
/** Builds a [HeaderInfo] for progressions built using the `indices` extension property. */
|
||||||
@@ -62,14 +62,13 @@ internal abstract class IndicesHandler(protected val context: CommonBackendConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class CollectionIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
internal class CollectionIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
extensionReceiver { it?.type?.isCollection() == true }
|
val callee = expression.symbol.owner
|
||||||
fqName { it == FqName("kotlin.collections.<get-indices>") }
|
return callee.valueParameters.isEmpty() &&
|
||||||
parameterCount { it == 0 }
|
callee.extensionReceiverParameter?.type?.isCollection() == true &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.collections.<get-indices>")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||||
get() = context.ir.symbols.collection.getPropertyGetter("size")!!.owner
|
get() = context.ir.symbols.collection.getPropertyGetter("size")!!.owner
|
||||||
}
|
}
|
||||||
@@ -77,31 +76,27 @@ internal class CollectionIndicesHandler(context: CommonBackendContext) : Indices
|
|||||||
internal class ArrayIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
internal class ArrayIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
||||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||||
|
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
extensionReceiver {
|
val callee = expression.symbol.owner
|
||||||
it != null && it.type.run {
|
return callee.valueParameters.isEmpty() &&
|
||||||
isArray() || isPrimitiveArray() || (supportsUnsignedArrays && isUnsignedArray())
|
callee.extensionReceiverParameter?.type?.let {
|
||||||
}
|
it.isArray() || it.isPrimitiveArray() || (supportsUnsignedArrays && it.isUnsignedArray())
|
||||||
}
|
} == true &&
|
||||||
fqName { it == FqName("kotlin.collections.<get-indices>") }
|
callee.kotlinFqName == FqName("kotlin.collections.<get-indices>")
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||||
get() = getClass()!!.getPropertyGetter("size")!!.owner
|
get() = getClass()!!.getPropertyGetter("size")!!.owner
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CharSequenceIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
internal class CharSequenceIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
extensionReceiver { it != null && it.type.run { isCharSequence() } }
|
val callee = expression.symbol.owner
|
||||||
fqName { it == FqName("kotlin.text.<get-indices>") }
|
return callee.valueParameters.isEmpty() &&
|
||||||
parameterCount { it == 0 }
|
callee.extensionReceiverParameter?.type?.isCharSequence() == true &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.text.<get-indices>")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||||
get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
|
get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-9
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||||
@@ -19,18 +18,15 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
|||||||
/** Builds a [HeaderInfo] for progressions built using the `rangeTo` function. */
|
/** Builds a [HeaderInfo] for progressions built using the `rangeTo` function. */
|
||||||
internal class RangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
internal class RangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||||
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
||||||
|
|
||||||
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||||
|
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
dispatchReceiver { it != null && it.type in progressionElementTypes }
|
val callee = expression.symbol.owner
|
||||||
fqName { it.pathSegments().last() == OperatorNameConventions.RANGE_TO }
|
return callee.valueParameters.singleOrNull()?.type in progressionElementTypes &&
|
||||||
parameterCount { it == 1 }
|
callee.dispatchReceiverParameter?.type in progressionElementTypes &&
|
||||||
parameter(0) { it.type in progressionElementTypes }
|
callee.name == OperatorNameConventions.RANGE_TO
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
|
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol) =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
val first = expression.dispatchReceiver!!
|
val first = expression.dispatchReceiver!!
|
||||||
|
|||||||
+8
-16
@@ -8,11 +8,10 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoBuilder
|
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.createIrCallMatcher
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.defaultType
|
import org.jetbrains.kotlin.ir.types.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for calls to reverse an iterable. */
|
/** Builds a [HeaderInfo] for calls to reverse an iterable. */
|
||||||
@@ -20,20 +19,13 @@ internal class ReversedHandler(context: CommonBackendContext, private val visito
|
|||||||
HeaderInfoHandler<IrCall, Nothing?> {
|
HeaderInfoHandler<IrCall, Nothing?> {
|
||||||
private val progressionClassesTypes = context.ir.symbols.progressionClasses.map { it.defaultType }.toSet()
|
private val progressionClassesTypes = context.ir.symbols.progressionClasses.map { it.defaultType }.toSet()
|
||||||
|
|
||||||
// Use Quantifier.ANY so we can handle all reversed iterables in the same manner.
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
private val matcher =
|
// TODO: Handle reversed String, Progression.withIndex(), etc.
|
||||||
createIrCallMatcher(Quantifier.ANY) {
|
val callee = expression.symbol.owner
|
||||||
// Matcher for reversed progression.
|
return callee.valueParameters.isEmpty() &&
|
||||||
callee {
|
callee.extensionReceiverParameter?.type in progressionClassesTypes &&
|
||||||
fqName { it == FqName("kotlin.ranges.reversed") }
|
callee.kotlinFqName == FqName("kotlin.ranges.reversed")
|
||||||
extensionReceiver { it != null && it.type in progressionClassesTypes }
|
}
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Handle reversed String, Progression.withIndex(), etc.
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
// Reverse the HeaderInfo from the underlying progression or array (if any).
|
// Reverse the HeaderInfo from the underlying progression or array (if any).
|
||||||
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol) =
|
||||||
|
|||||||
+7
-12
@@ -9,8 +9,6 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.singleArgumentExtension
|
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
@@ -18,10 +16,11 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.addArgument
|
import org.jetbrains.kotlin.ir.expressions.addArgument
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.defaultType
|
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||||
import org.jetbrains.kotlin.ir.types.isInt
|
import org.jetbrains.kotlin.ir.types.isInt
|
||||||
import org.jetbrains.kotlin.ir.types.isLong
|
import org.jetbrains.kotlin.ir.types.isLong
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.ir.util.shallowCopy
|
import org.jetbrains.kotlin.ir.util.shallowCopy
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
@@ -30,17 +29,13 @@ import kotlin.math.absoluteValue
|
|||||||
internal class StepHandler(
|
internal class StepHandler(
|
||||||
private val context: CommonBackendContext, private val visitor: HeaderInfoBuilder
|
private val context: CommonBackendContext, private val visitor: HeaderInfoBuilder
|
||||||
) : HeaderInfoHandler<IrCall, ProgressionType> {
|
) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||||
private val symbols = context.ir.symbols
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
|
val callee = expression.symbol.owner
|
||||||
private val matcher = SimpleCalleeMatcher {
|
return callee.valueParameters.singleOrNull()?.type?.let { it.isInt() || it.isLong() } == true &&
|
||||||
singleArgumentExtension(
|
callee.extensionReceiverParameter?.type?.classOrNull in context.ir.symbols.progressionClasses &&
|
||||||
FqName("kotlin.ranges.step"),
|
callee.kotlinFqName == FqName("kotlin.ranges.step")
|
||||||
symbols.progressionClasses.map { it.defaultType })
|
|
||||||
parameter(0) { it.type.isInt() || it.type.isLong() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
// Retrieve the HeaderInfo from the underlying progression (if any).
|
// Retrieve the HeaderInfo from the underlying progression (if any).
|
||||||
|
|||||||
+7
-10
@@ -8,26 +8,23 @@ package org.jetbrains.kotlin.backend.common.lower.loops.handlers
|
|||||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
import org.jetbrains.kotlin.backend.common.lower.loops.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.singleArgumentExtension
|
|
||||||
import org.jetbrains.kotlin.ir.builders.irInt
|
import org.jetbrains.kotlin.ir.builders.irInt
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for progressions built using the `until` extension function. */
|
/** Builds a [HeaderInfo] for progressions built using the `until` extension function. */
|
||||||
internal class UntilHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
internal class UntilHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||||
private val symbols = context.ir.symbols
|
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||||
private val progressionElementTypes = symbols.progressionElementTypes
|
|
||||||
|
|
||||||
private val matcher = SimpleCalleeMatcher {
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
|
val callee = expression.symbol.owner
|
||||||
parameterCount { it == 1 }
|
return callee.valueParameters.singleOrNull()?.type in progressionElementTypes &&
|
||||||
parameter(0) { it.type in progressionElementTypes }
|
callee.extensionReceiverParameter?.type in progressionElementTypes &&
|
||||||
|
callee.kotlinFqName == FqName("kotlin.ranges.until")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
||||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||||
ProgressionHeaderInfo(
|
ProgressionHeaderInfo(
|
||||||
|
|||||||
+19
-29
@@ -10,8 +10,6 @@ import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfo
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
import org.jetbrains.kotlin.backend.common.lower.loops.HeaderInfoHandler
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.NestedHeaderInfoBuilderForWithIndex
|
import org.jetbrains.kotlin.backend.common.lower.loops.NestedHeaderInfoBuilderForWithIndex
|
||||||
import org.jetbrains.kotlin.backend.common.lower.loops.WithIndexHeaderInfo
|
import org.jetbrains.kotlin.backend.common.lower.loops.WithIndexHeaderInfo
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.Quantifier
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.matchers.createIrCallMatcher
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.isArray
|
import org.jetbrains.kotlin.ir.types.isArray
|
||||||
@@ -20,40 +18,32 @@ import org.jetbrains.kotlin.ir.types.isSequence
|
|||||||
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
|
import org.jetbrains.kotlin.ir.types.isSubtypeOfClass
|
||||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
||||||
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||||
|
|
||||||
/** Builds a [HeaderInfo] for calls to `withIndex()`. */
|
/** Builds a [HeaderInfo] for calls to `withIndex()`. */
|
||||||
internal class WithIndexHandler(
|
internal class WithIndexHandler(
|
||||||
context: CommonBackendContext, private val visitor: NestedHeaderInfoBuilderForWithIndex
|
private val context: CommonBackendContext,
|
||||||
|
private val visitor: NestedHeaderInfoBuilderForWithIndex
|
||||||
) : HeaderInfoHandler<IrCall, Nothing?> {
|
) : HeaderInfoHandler<IrCall, Nothing?> {
|
||||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||||
|
|
||||||
// Use Quantifier.ANY so we can handle all `withIndex()` calls in the same manner.
|
override fun matchIterable(expression: IrCall): Boolean {
|
||||||
private val matcher =
|
val callee = expression.symbol.owner
|
||||||
createIrCallMatcher(Quantifier.ANY) {
|
if (callee.valueParameters.isNotEmpty() || callee.name.asString() != "withIndex") return false
|
||||||
callee {
|
|
||||||
fqName { it == FqName("kotlin.collections.withIndex") }
|
|
||||||
extensionReceiver {
|
|
||||||
it != null && it.type.run {
|
|
||||||
isArray() || isPrimitiveArray() || isIterable() ||
|
|
||||||
(supportsUnsignedArrays && isUnsignedArray())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
|
||||||
callee {
|
|
||||||
fqName { it == FqName("kotlin.text.withIndex") }
|
|
||||||
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.charSequence) }
|
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
|
||||||
callee {
|
|
||||||
fqName { it == FqName("kotlin.sequences.withIndex") }
|
|
||||||
extensionReceiver { it != null && it.type.run { isSequence() } }
|
|
||||||
parameterCount { it == 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
return when (callee.kotlinFqName.asString()) {
|
||||||
|
"kotlin.collections.withIndex" ->
|
||||||
|
callee.extensionReceiverParameter?.type?.run {
|
||||||
|
isArray() || isPrimitiveArray() || isIterable() ||
|
||||||
|
(supportsUnsignedArrays && isUnsignedArray())
|
||||||
|
} == true
|
||||||
|
"kotlin.text.withIndex" ->
|
||||||
|
callee.extensionReceiverParameter?.type?.isSubtypeOfClass(context.ir.symbols.charSequence) == true
|
||||||
|
"kotlin.sequences.withIndex" ->
|
||||||
|
callee.extensionReceiverParameter?.type?.isSequence() == true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo? {
|
override fun build(expression: IrCall, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo? {
|
||||||
// WithIndexHeaderInfo is a composite that contains the HeaderInfo for the underlying iterable (if any).
|
// WithIndexHeaderInfo is a composite that contains the HeaderInfo for the underlying iterable (if any).
|
||||||
|
|||||||
-77
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.lower.matchers
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|
||||||
|
|
||||||
internal interface IrCallMatcher : (IrCall) -> Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IrCallMatcher that puts restrictions only on its callee.
|
|
||||||
*/
|
|
||||||
internal class SimpleCalleeMatcher(
|
|
||||||
restrictions: IrFunctionMatcherContainer.() -> Unit
|
|
||||||
) : IrCallMatcher {
|
|
||||||
|
|
||||||
private val calleeRestriction: IrFunctionMatcher = createIrFunctionRestrictions(restrictions)
|
|
||||||
|
|
||||||
override fun invoke(call: IrCall) = calleeRestriction(call.symbol.owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class IrCallExtensionReceiverMatcher(
|
|
||||||
val restriction: (IrExpression?) -> Boolean
|
|
||||||
) : IrCallMatcher {
|
|
||||||
override fun invoke(call: IrCall) = restriction(call.extensionReceiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class IrCallDispatchReceiverMatcher(
|
|
||||||
val restriction: (IrExpression?) -> Boolean
|
|
||||||
) : IrCallMatcher {
|
|
||||||
override fun invoke(call: IrCall) = restriction(call.dispatchReceiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class IrCallOriginMatcher(
|
|
||||||
val restriction: (IrStatementOrigin?) -> Boolean
|
|
||||||
) : IrCallMatcher {
|
|
||||||
override fun invoke(call: IrCall) = restriction(call.origin)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum class Quantifier { ALL, ANY }
|
|
||||||
|
|
||||||
internal open class IrCallMatcherContainer(private val quantifier: Quantifier) : IrCallMatcher {
|
|
||||||
|
|
||||||
private val matchers = mutableListOf<IrCallMatcher>()
|
|
||||||
|
|
||||||
fun add(matcher: IrCallMatcher) {
|
|
||||||
matchers += matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
fun extensionReceiver(restriction: (IrExpression?) -> Boolean) =
|
|
||||||
add(IrCallExtensionReceiverMatcher(restriction))
|
|
||||||
|
|
||||||
fun origin(restriction: (IrStatementOrigin?) -> Boolean) =
|
|
||||||
add(IrCallOriginMatcher(restriction))
|
|
||||||
|
|
||||||
fun callee(restrictions: IrFunctionMatcherContainer.() -> Unit) {
|
|
||||||
add(SimpleCalleeMatcher(restrictions))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dispatchReceiver(restriction: (IrExpression?) -> Boolean) =
|
|
||||||
add(IrCallDispatchReceiverMatcher(restriction))
|
|
||||||
|
|
||||||
override fun invoke(call: IrCall) = when (quantifier) {
|
|
||||||
Quantifier.ALL -> matchers.all { it(call) }
|
|
||||||
Quantifier.ANY -> matchers.any { it(call) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun createIrCallMatcher(
|
|
||||||
quantifier: Quantifier = Quantifier.ALL,
|
|
||||||
restrictions: IrCallMatcherContainer.() -> Unit
|
|
||||||
) =
|
|
||||||
IrCallMatcherContainer(quantifier).apply(restrictions)
|
|
||||||
-98
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.lower.matchers
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
|
||||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
|
|
||||||
internal interface IrFunctionMatcher : (IrFunction) -> Boolean
|
|
||||||
|
|
||||||
internal class ParameterMatcher(
|
|
||||||
val index: Int,
|
|
||||||
val restriction: (IrValueParameter) -> Boolean
|
|
||||||
) : IrFunctionMatcher {
|
|
||||||
|
|
||||||
override fun invoke(function: IrFunction): Boolean {
|
|
||||||
val params = function.valueParameters
|
|
||||||
return params.size > index && restriction(params[index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class DispatchReceiverMatcher(
|
|
||||||
val restriction: (IrValueParameter?) -> Boolean
|
|
||||||
) : IrFunctionMatcher {
|
|
||||||
|
|
||||||
override fun invoke(function: IrFunction): Boolean {
|
|
||||||
return restriction(function.dispatchReceiverParameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ExtensionReceiverMatcher(
|
|
||||||
val restriction: (IrValueParameter?) -> Boolean
|
|
||||||
) : IrFunctionMatcher {
|
|
||||||
|
|
||||||
override fun invoke(function: IrFunction): Boolean {
|
|
||||||
return restriction(function.extensionReceiverParameter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ParameterCountMatcher(
|
|
||||||
val restriction: (Int) -> Boolean
|
|
||||||
) : IrFunctionMatcher {
|
|
||||||
|
|
||||||
override fun invoke(function: IrFunction): Boolean {
|
|
||||||
return restriction(function.valueParameters.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class FqNameMatcher(
|
|
||||||
val restriction: (FqName) -> Boolean
|
|
||||||
) : IrFunctionMatcher {
|
|
||||||
override fun invoke(function: IrFunction): Boolean {
|
|
||||||
return restriction(function.kotlinFqName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal open class IrFunctionMatcherContainer : IrFunctionMatcher {
|
|
||||||
private val restrictions = mutableListOf<IrFunctionMatcher>()
|
|
||||||
|
|
||||||
fun add(restriction: IrFunctionMatcher) {
|
|
||||||
restrictions += restriction
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fqName(restriction: (FqName) -> Boolean) =
|
|
||||||
add(FqNameMatcher(restriction))
|
|
||||||
|
|
||||||
fun parameterCount(restriction: (Int) -> Boolean) =
|
|
||||||
add(ParameterCountMatcher(restriction))
|
|
||||||
|
|
||||||
fun extensionReceiver(restriction: (IrValueParameter?) -> Boolean) =
|
|
||||||
add(ExtensionReceiverMatcher(restriction))
|
|
||||||
|
|
||||||
fun dispatchReceiver(restriction: (IrValueParameter?) -> Boolean) =
|
|
||||||
add(DispatchReceiverMatcher(restriction))
|
|
||||||
|
|
||||||
fun parameter(index: Int, restriction: (IrValueParameter) -> Boolean) =
|
|
||||||
add(ParameterMatcher(index, restriction))
|
|
||||||
|
|
||||||
override fun invoke(function: IrFunction) = restrictions.all { it(function) }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun createIrFunctionRestrictions(restrictions: IrFunctionMatcherContainer.() -> Unit) =
|
|
||||||
IrFunctionMatcherContainer().apply(restrictions)
|
|
||||||
|
|
||||||
internal fun IrFunctionMatcherContainer.singleArgumentExtension(
|
|
||||||
fqName: FqName,
|
|
||||||
types: Collection<IrType>
|
|
||||||
): IrFunctionMatcherContainer {
|
|
||||||
extensionReceiver { it != null && it.type in types }
|
|
||||||
parameterCount { it == 1 }
|
|
||||||
fqName { it == fqName }
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user