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.lower.loops.*
|
||||
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.builtins.PrimitiveType
|
||||
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.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
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.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -60,14 +56,14 @@ private class Transformer(
|
||||
val context: CommonBackendContext,
|
||||
val container: IrSymbolOwner
|
||||
) : IrElementTransformerVoidWithContext() {
|
||||
|
||||
private val headerInfoBuilder = RangeHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
||||
fun getScopeOwnerSymbol() = currentScope?.scope?.scopeOwnerSymbol ?: container.symbol
|
||||
|
||||
val stdlibExtensionContainsCallMatcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.closedRange) }
|
||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.CONTAINS}") }
|
||||
parameterCount { it == 1 }
|
||||
private fun matchStdlibExtensionContainsCall(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.size == 1 &&
|
||||
callee.extensionReceiverParameter?.type?.isSubtypeOfClass(context.ir.symbols.closedRange) == true &&
|
||||
callee.kotlinFqName == FqName("kotlin.ranges.${OperatorNameConventions.CONTAINS}")
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
@@ -89,7 +85,7 @@ private class Transformer(
|
||||
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.
|
||||
// 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.
|
||||
@@ -412,15 +408,13 @@ internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeO
|
||||
|
||||
/** Builds a [HeaderInfo] for closed floating-point ranges built using the `rangeTo` function. */
|
||||
internal object FloatingPointRangeToHandler : HeaderInfoHandler<IrCall, Nothing?> {
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
|
||||
extensionReceiver { it != null && it.type.run { isFloat() || isDouble() } }
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type.run { isFloat() || isDouble() } }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.type?.let { it.isFloat() || it.isDouble() } == true &&
|
||||
callee.extensionReceiverParameter?.type?.let { it.isFloat() || it.isDouble() } == 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) =
|
||||
FloatingPointRangeHeaderInfo(
|
||||
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. */
|
||||
internal class ComparableRangeToHandler(context: CommonBackendContext) : HeaderInfoHandler<IrCall, Nothing?> {
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
fqName { it == FqName("kotlin.ranges.${OperatorNameConventions.RANGE_TO}") }
|
||||
extensionReceiver { it != null && it.type.isSubtypeOfClass(context.ir.symbols.comparable) }
|
||||
parameterCount { it == 1 }
|
||||
internal class ComparableRangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, Nothing?> {
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.size == 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) =
|
||||
ComparableRangeInfo(
|
||||
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.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
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.impl.IrConstImpl
|
||||
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.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -26,8 +26,8 @@ class StringTrimLowering(val context: CommonBackendContext) : FileLoweringPass,
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
return when {
|
||||
trimIndentMatcher(expression) -> maybeComputeTrimIndent(expression)
|
||||
trimMarginMatcher(expression) -> maybeComputeTrimMargin(expression)
|
||||
matchTrimIndent(expression) -> maybeComputeTrimIndent(expression)
|
||||
matchTrimMargin(expression) -> maybeComputeTrimMargin(expression)
|
||||
else -> super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
@@ -64,20 +64,21 @@ class StringTrimLowering(val context: CommonBackendContext) : FileLoweringPass,
|
||||
return null
|
||||
}
|
||||
|
||||
private val trimIndentMatcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it != null && it.type.isString() }
|
||||
fqName { it == TRIM_INDENT_FQ_NAME }
|
||||
parameterCount { it == 0 }
|
||||
private fun matchTrimIndent(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
callee.extensionReceiverParameter?.type?.isString() == true &&
|
||||
callee.kotlinFqName == TRIM_INDENT_FQ_NAME
|
||||
}
|
||||
|
||||
private val trimMarginMatcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it != null && it.type.isString() }
|
||||
fqName { it == TRIM_MARGIN_FQ_NAME }
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type.isString() }
|
||||
private fun matchTrimMargin(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.type?.isString() == true &&
|
||||
callee.extensionReceiverParameter?.type?.isString() == true &&
|
||||
callee.kotlinFqName == TRIM_MARGIN_FQ_NAME
|
||||
}
|
||||
|
||||
private val TRIM_MARGIN_FQ_NAME = FqName.fromSegments(listOf("kotlin", "text", "trimMargin"))
|
||||
private val TRIM_INDENT_FQ_NAME = FqName.fromSegments(listOf("kotlin", "text", "trimIndent"))
|
||||
private val TRIM_MARGIN_FQ_NAME = FqName("kotlin.text.trimMargin")
|
||||
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.ir.Symbols
|
||||
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.IrStatement
|
||||
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),
|
||||
* the handler can build a [HeaderInfo] from the iterable.
|
||||
*/
|
||||
val iteratorCallMatcher: IrCallMatcher?
|
||||
get() = null
|
||||
fun matchIteratorCall(call: IrCall): Boolean = true
|
||||
|
||||
/** Builds a [HeaderInfo] from the expression. */
|
||||
fun build(expression: E, data: D, scopeOwner: IrSymbol): HeaderInfo?
|
||||
|
||||
fun handle(expression: E, iteratorCall: IrCall?, data: D, scopeOwner: IrSymbol) =
|
||||
if ((iteratorCall == null || iteratorCallMatcher == null || iteratorCallMatcher!!(iteratorCall)) && matchIterable(expression)) {
|
||||
fun handle(expression: E, iteratorCall: IrCall?, data: D, scopeOwner: IrSymbol): HeaderInfo? =
|
||||
if ((iteratorCall == null || matchIteratorCall(iteratorCall)) && matchIterable(expression)) {
|
||||
build(expression, data, scopeOwner)
|
||||
} else {
|
||||
null
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
internal class DefaultIterableHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrExpression, Nothing?> {
|
||||
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 =
|
||||
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 rangeClassesTypes = symbols.rangeClasses.map { it.defaultType }.toSet()
|
||||
|
||||
override fun matchIterable(expression: IrExpression) = ProgressionType.fromIrType(
|
||||
expression.type,
|
||||
symbols,
|
||||
allowUnsignedBounds
|
||||
) != null
|
||||
override fun matchIterable(expression: IrExpression): Boolean =
|
||||
ProgressionType.fromIrType(expression.type, symbols, allowUnsignedBounds) != null
|
||||
|
||||
override fun build(expression: IrExpression, data: Nothing?, scopeOwner: IrSymbol): HeaderInfo =
|
||||
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?> {
|
||||
private val sequenceClassSymbol = context.ir.symbols.sequence
|
||||
|
||||
override fun matchIterable(expression: IrExpression) =
|
||||
override fun matchIterable(expression: IrExpression): Boolean =
|
||||
sequenceClassSymbol != null && expression.type.isSubtypeOfClass(sequenceClassSymbol)
|
||||
|
||||
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.lower.createIrBuilder
|
||||
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.expressions.IrCall
|
||||
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.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
/** Builds a [HeaderInfo] for progressions built using the `downTo` extension function. */
|
||||
internal class DownToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
||||
|
||||
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
singleArgumentExtension(FqName("kotlin.ranges.downTo"), progressionElementTypes)
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type in progressionElementTypes }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.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) =
|
||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||
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.HeaderInfoHandler
|
||||
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.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
@@ -77,22 +74,14 @@ abstract class IndexedGetIterationHandler(
|
||||
internal class ArrayIterationHandler(context: CommonBackendContext) : IndexedGetIterationHandler(context, canCacheLast = true) {
|
||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||
|
||||
override fun matchIterable(expression: IrExpression) =
|
||||
expression.type.run { isArrayType() } ||
|
||||
expression.run {
|
||||
this is IrCall && reversedArrayMatcher(this)
|
||||
}
|
||||
override fun matchIterable(expression: IrExpression): Boolean {
|
||||
if (expression.type.isArrayType()) return true
|
||||
|
||||
private val reversedArrayMatcher =
|
||||
createIrCallMatcher(Quantifier.ANY) {
|
||||
callee {
|
||||
fqName { it == FqName("kotlin.collections.reversed") }
|
||||
extensionReceiver {
|
||||
it != null && it.type.run { isArray() || isPrimitiveArray() }
|
||||
}
|
||||
parameterCount { it == 0 }
|
||||
}
|
||||
}
|
||||
val callee = (expression as? IrCall)?.symbol?.owner ?: return false
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
callee.extensionReceiverParameter?.type?.let { it.isArray() || it.isPrimitiveArray() } == true &&
|
||||
callee.kotlinFqName == FqName("kotlin.collections.reversed")
|
||||
}
|
||||
|
||||
override val IrType.sizePropertyGetter
|
||||
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
|
||||
* that "last" is re-evaluated with each iteration of the loop.
|
||||
*/
|
||||
internal open class CharSequenceIterationHandler(context: CommonBackendContext, canCacheLast: Boolean = false) :
|
||||
IndexedGetIterationHandler(context, canCacheLast) {
|
||||
override fun matchIterable(expression: IrExpression) = expression.type.isSubtypeOfClass(context.ir.symbols.charSequence)
|
||||
internal open class CharSequenceIterationHandler(
|
||||
context: CommonBackendContext,
|
||||
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`).
|
||||
// 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.
|
||||
override val iteratorCallMatcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it != null && it.type.run { isCharSequence() } }
|
||||
fqName { it == FqName("kotlin.text.${OperatorNameConventions.ITERATOR}") }
|
||||
parameterCount { it == 0 }
|
||||
override fun matchIteratorCall(call: IrCall): Boolean {
|
||||
val callee = call.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
callee.extensionReceiverParameter?.type?.isCharSequence() == true &&
|
||||
callee.kotlinFqName == FqName("kotlin.text.${OperatorNameConventions.ITERATOR}")
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
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
|
||||
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.lower.createIrBuilder
|
||||
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.irInt
|
||||
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.isPrimitiveArray
|
||||
import org.jetbrains.kotlin.ir.util.isUnsignedArray
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
/** 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) {
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it?.type?.isCollection() == true }
|
||||
fqName { it == FqName("kotlin.collections.<get-indices>") }
|
||||
parameterCount { it == 0 }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
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
|
||||
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) {
|
||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
extensionReceiver {
|
||||
it != null && it.type.run {
|
||||
isArray() || isPrimitiveArray() || (supportsUnsignedArrays && isUnsignedArray())
|
||||
}
|
||||
}
|
||||
fqName { it == FqName("kotlin.collections.<get-indices>") }
|
||||
parameterCount { it == 0 }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
callee.extensionReceiverParameter?.type?.let {
|
||||
it.isArray() || it.isPrimitiveArray() || (supportsUnsignedArrays && it.isUnsignedArray())
|
||||
} == true &&
|
||||
callee.kotlinFqName == FqName("kotlin.collections.<get-indices>")
|
||||
}
|
||||
|
||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
||||
|
||||
override val IrType.sizePropertyGetter: IrSimpleFunction
|
||||
get() = getClass()!!.getPropertyGetter("size")!!.owner
|
||||
}
|
||||
|
||||
internal class CharSequenceIndicesHandler(context: CommonBackendContext) : IndicesHandler(context) {
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
extensionReceiver { it != null && it.type.run { isCharSequence() } }
|
||||
fqName { it == FqName("kotlin.text.<get-indices>") }
|
||||
parameterCount { it == 0 }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
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
|
||||
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.lower.createIrBuilder
|
||||
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.expressions.*
|
||||
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. */
|
||||
internal class RangeToHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||
private val preferJavaLikeCounterLoop = context.preferJavaLikeCounterLoop
|
||||
|
||||
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
dispatchReceiver { it != null && it.type in progressionElementTypes }
|
||||
fqName { it.pathSegments().last() == OperatorNameConventions.RANGE_TO }
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type in progressionElementTypes }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.type in progressionElementTypes &&
|
||||
callee.dispatchReceiverParameter?.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) =
|
||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||
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.lower.loops.HeaderInfoBuilder
|
||||
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.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
/** Builds a [HeaderInfo] for calls to reverse an iterable. */
|
||||
@@ -20,20 +19,13 @@ internal class ReversedHandler(context: CommonBackendContext, private val visito
|
||||
HeaderInfoHandler<IrCall, Nothing?> {
|
||||
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.
|
||||
private val matcher =
|
||||
createIrCallMatcher(Quantifier.ANY) {
|
||||
// Matcher for reversed progression.
|
||||
callee {
|
||||
fqName { it == 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)
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
// TODO: Handle reversed String, Progression.withIndex(), etc.
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.isEmpty() &&
|
||||
callee.extensionReceiverParameter?.type in progressionClassesTypes &&
|
||||
callee.kotlinFqName == FqName("kotlin.ranges.reversed")
|
||||
}
|
||||
|
||||
// Reverse the HeaderInfo from the underlying progression or array (if any).
|
||||
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.createIrBuilder
|
||||
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.builders.*
|
||||
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.addArgument
|
||||
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.isLong
|
||||
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.name.FqName
|
||||
import kotlin.math.absoluteValue
|
||||
@@ -30,17 +29,13 @@ import kotlin.math.absoluteValue
|
||||
internal class StepHandler(
|
||||
private val context: CommonBackendContext, private val visitor: HeaderInfoBuilder
|
||||
) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
singleArgumentExtension(
|
||||
FqName("kotlin.ranges.step"),
|
||||
symbols.progressionClasses.map { it.defaultType })
|
||||
parameter(0) { it.type.isInt() || it.type.isLong() }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.type?.let { it.isInt() || it.isLong() } == true &&
|
||||
callee.extensionReceiverParameter?.type?.classOrNull in context.ir.symbols.progressionClasses &&
|
||||
callee.kotlinFqName == FqName("kotlin.ranges.step")
|
||||
}
|
||||
|
||||
override fun matchIterable(expression: IrCall): Boolean = matcher(expression)
|
||||
|
||||
override fun build(expression: IrCall, data: ProgressionType, scopeOwner: IrSymbol): HeaderInfo? =
|
||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||
// 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.lower.createIrBuilder
|
||||
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.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
/** Builds a [HeaderInfo] for progressions built using the `until` extension function. */
|
||||
internal class UntilHandler(private val context: CommonBackendContext) : HeaderInfoHandler<IrCall, ProgressionType> {
|
||||
private val symbols = context.ir.symbols
|
||||
private val progressionElementTypes = symbols.progressionElementTypes
|
||||
private val progressionElementTypes = context.ir.symbols.progressionElementTypes
|
||||
|
||||
private val matcher = SimpleCalleeMatcher {
|
||||
singleArgumentExtension(FqName("kotlin.ranges.until"), progressionElementTypes)
|
||||
parameterCount { it == 1 }
|
||||
parameter(0) { it.type in progressionElementTypes }
|
||||
override fun matchIterable(expression: IrCall): Boolean {
|
||||
val callee = expression.symbol.owner
|
||||
return callee.valueParameters.singleOrNull()?.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? =
|
||||
with(context.createIrBuilder(scopeOwner, expression.startOffset, expression.endOffset)) {
|
||||
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.NestedHeaderInfoBuilderForWithIndex
|
||||
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.symbols.IrSymbol
|
||||
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.util.isPrimitiveArray
|
||||
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()`. */
|
||||
internal class WithIndexHandler(
|
||||
context: CommonBackendContext, private val visitor: NestedHeaderInfoBuilderForWithIndex
|
||||
private val context: CommonBackendContext,
|
||||
private val visitor: NestedHeaderInfoBuilderForWithIndex
|
||||
) : HeaderInfoHandler<IrCall, Nothing?> {
|
||||
private val supportsUnsignedArrays = context.optimizeLoopsOverUnsignedArrays
|
||||
|
||||
// Use Quantifier.ANY so we can handle all `withIndex()` calls in the same manner.
|
||||
private val matcher =
|
||||
createIrCallMatcher(Quantifier.ANY) {
|
||||
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 {
|
||||
val callee = expression.symbol.owner
|
||||
if (callee.valueParameters.isNotEmpty() || callee.name.asString() != "withIndex") return false
|
||||
|
||||
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? {
|
||||
// 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