From d2b66e50047cffc8753fffdc85724e343cd9b390 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Sun, 11 Dec 2022 23:24:11 +0100 Subject: [PATCH] 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. --- .../common/lower/RangeContainsLowering.kt | 43 ++++---- .../common/lower/StringTrimLowering.kt | 29 +++--- .../backend/common/lower/loops/HeaderInfo.kt | 8 +- .../loops/handlers/DefaultIterableHandler.kt | 3 +- .../handlers/DefaultProgressionHandler.kt | 7 +- .../loops/handlers/DefaultSequenceHandler.kt | 2 +- .../lower/loops/handlers/DownToHandler.kt | 15 ++- .../handlers/IndexedGetIterationHandlers.kt | 46 ++++----- .../lower/loops/handlers/IndicesHandlers.kt | 41 ++++---- .../lower/loops/handlers/RangeToHandler.kt | 14 +-- .../lower/loops/handlers/ReversedHandler.kt | 24 ++--- .../lower/loops/handlers/StepHandler.kt | 19 ++-- .../lower/loops/handlers/UntilHandler.kt | 17 ++-- .../lower/loops/handlers/WithIndexHandler.kt | 48 ++++----- .../common/lower/matchers/IrCallMatcher.kt | 77 --------------- .../lower/matchers/IrFunctionMatcher.kt | 98 ------------------- 16 files changed, 131 insertions(+), 360 deletions(-) delete mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrCallMatcher.kt delete mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt index 347454f44f5..b9335a05730 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt @@ -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 { - 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 { - 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 { + 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!!, diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringTrimLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringTrimLowering.kt index cbc896efe0f..2d74ff3a2ae 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringTrimLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/StringTrimLowering.kt @@ -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") } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt index 27af592e1f6..6a5c6fc0dba 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/HeaderInfo.kt @@ -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 { * 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 diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultIterableHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultIterableHandler.kt index aafbbf29c35..aff0514ccb2 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultIterableHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultIterableHandler.kt @@ -22,7 +22,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions internal class DefaultIterableHandler(private val context: CommonBackendContext) : HeaderInfoHandler { 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)) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultProgressionHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultProgressionHandler.kt index 2fdb45cba94..0c84332ebba 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultProgressionHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultProgressionHandler.kt @@ -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)) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultSequenceHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultSequenceHandler.kt index 0b485b07f16..900384d9b8b 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultSequenceHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DefaultSequenceHandler.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions internal class DefaultSequenceHandler(private val context: CommonBackendContext) : HeaderInfoHandler { 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 = diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt index c303638f355..36e0fcc691f 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/DownToHandler.kt @@ -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 { 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!! diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndexedGetIterationHandlers.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndexedGetIterationHandlers.kt index 685ccde9614..313c41e9173 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndexedGetIterationHandlers.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndexedGetIterationHandlers.kt @@ -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 diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndicesHandlers.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndicesHandlers.kt index 8d7344bf6b0..8f9b5c3927d 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndicesHandlers.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/IndicesHandlers.kt @@ -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.") } - 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.") } - 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.") } - 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.") } - 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.") } - 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.") } - override fun matchIterable(expression: IrCall): Boolean = matcher(expression) - override val IrType.sizePropertyGetter: IrSimpleFunction get() = context.ir.symbols.charSequence.getPropertyGetter("length")!!.owner } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt index 47d4510e339..7d3be45d481 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/RangeToHandler.kt @@ -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 { 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!! diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/ReversedHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/ReversedHandler.kt index e073f9e133f..3b1df8bd100 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/ReversedHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/ReversedHandler.kt @@ -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 { 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) = diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/StepHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/StepHandler.kt index 45f356de202..bac976b83d1 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/StepHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/StepHandler.kt @@ -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 { - 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). diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt index 1610a51887e..53d53efa065 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/UntilHandler.kt @@ -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 { - 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( diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/WithIndexHandler.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/WithIndexHandler.kt index c0b8fd0d7bd..12eb35550ad 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/WithIndexHandler.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/handlers/WithIndexHandler.kt @@ -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 { 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). diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrCallMatcher.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrCallMatcher.kt deleted file mode 100644 index d2fc995ec67..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrCallMatcher.kt +++ /dev/null @@ -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() - - 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) \ No newline at end of file diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt deleted file mode 100644 index dde73bda50e..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/matchers/IrFunctionMatcher.kt +++ /dev/null @@ -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() - - 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 -): IrFunctionMatcherContainer { - extensionReceiver { it != null && it.type in types } - parameterCount { it == 1 } - fqName { it == fqName } - return this -}