From 297361f0c801ef9b4d99615b1b213360bbeac99d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 12 Oct 2020 14:37:53 +0200 Subject: [PATCH] IR: remove FunctionLoweringPass, refactor usages to FileLoweringPass FunctionLoweringPass didn't add much value over FileLoweringPass, but had a hidden footgun (like ClassLoweringPass) in that if your lowering pass invoked a visitor/transformer on the function body and you forgot to override visitFunction to stop visiting nested functions, runOnFilePostfix would work with the complexity of the squared number of nesting levels. It looks like this was happening with K/N's DataClassOperatorsLowering (I haven't measured though). (cherry picked from commit 822410a647560826e8cce96921eae32f237cf335) --- .../konan/lower/DataClassOperatorsLowering.kt | 99 ++++++++++--------- .../konan/lower/TypeOperatorLowering.kt | 49 +++------ 2 files changed, 62 insertions(+), 86 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt index 0bc7e206c4d..a7811d311e3 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DataClassOperatorsLowering.kt @@ -5,73 +5,76 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.FunctionLoweringPass +import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.util.irCall -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid - -internal class DataClassOperatorsLowering(val context: Context): FunctionLoweringPass { +import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +internal class DataClassOperatorsLowering(val context: Context) : FileLoweringPass, IrElementTransformer { private val irBuiltins = context.irModule!!.irBuiltins - override fun lower(irFunction: IrFunction) { - irFunction.transformChildrenVoid(object: IrElementTransformerVoid() { - override fun visitCall(expression: IrCall): IrExpression { - expression.transformChildrenVoid(this) + override fun lower(irFile: IrFile) { + irFile.transformChildren(this, null) + } - if (expression.symbol != irBuiltins.dataClassArrayMemberToStringSymbol - && expression.symbol != irBuiltins.dataClassArrayMemberHashCodeSymbol) - return expression + override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = + super.visitFunction(declaration, declaration) - val argument = expression.getValueArgument(0)!! - val argumentClassifier = argument.type.classifierOrFail + override fun visitCall(expression: IrCall, data: IrFunction?): IrExpression { + expression.transformChildren(this, data) - val isToString = expression.symbol == irBuiltins.dataClassArrayMemberToStringSymbol - val newCalleeSymbol = if (isToString) - context.ir.symbols.arrayContentToString[argumentClassifier]!! - else - context.ir.symbols.arrayContentHashCode[argumentClassifier]!! + if (expression.symbol != irBuiltins.dataClassArrayMemberToStringSymbol + && expression.symbol != irBuiltins.dataClassArrayMemberHashCodeSymbol) + return expression - val newCallee = newCalleeSymbol.owner + val argument = expression.getValueArgument(0)!! + val argumentClassifier = argument.type.classifierOrFail - val startOffset = expression.startOffset - val endOffset = expression.endOffset - val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset) + val isToString = expression.symbol == irBuiltins.dataClassArrayMemberToStringSymbol + val newCalleeSymbol = if (isToString) + context.ir.symbols.arrayContentToString[argumentClassifier]!! + else + context.ir.symbols.arrayContentHashCode[argumentClassifier]!! - return irBuilder.run { - // TODO: use more precise type arguments. - val typeArguments = (0 until newCallee.typeParameters.size).map { irBuiltins.anyNType } + val newCallee = newCalleeSymbol.owner - if (!argument.type.isSimpleTypeWithQuestionMark) { - irCall(newCallee, typeArguments).apply { - extensionReceiver = argument - } - } else { - irBlock(argument) { - val tmp = irTemporary(argument) - val call = irCall(newCallee, typeArguments).apply { - extensionReceiver = irGet(tmp) - } - +irIfThenElse(call.type, - irEqeqeq(irGet(tmp), irNull()), - if (isToString) - irString("null") - else - irInt(0), - call) - } + val startOffset = expression.startOffset + val endOffset = expression.endOffset + val irBuilder = context.createIrBuilder(data!!.symbol, startOffset, endOffset) + + return irBuilder.run { + // TODO: use more precise type arguments. + val typeArguments = (0 until newCallee.typeParameters.size).map { irBuiltins.anyNType } + + if (!argument.type.isSimpleTypeWithQuestionMark) { + irCall(newCallee, typeArguments).apply { + extensionReceiver = argument + } + } else { + irBlock(argument) { + val tmp = irTemporary(argument) + val call = irCall(newCallee, typeArguments).apply { + extensionReceiver = irGet(tmp) } + +irIfThenElse(call.type, + irEqeqeq(irGet(tmp), irNull()), + if (isToString) + irString("null") + else + irInt(0), + call) } } - }) + } } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt index 9158df1b601..f33aad224d5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TypeOperatorLowering.kt @@ -6,59 +6,34 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.FunctionLoweringPass -import org.jetbrains.kotlin.backend.common.lower.at -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlock -import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.konan.ir.containsNull import org.jetbrains.kotlin.backend.konan.ir.isSubtypeOf -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.makeNotNull import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.irCall -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -/** - * This lowering pass lowers some [IrTypeOperatorCall]s. - */ -internal class TypeOperatorLowering(val context: CommonBackendContext) : FunctionLoweringPass { - override fun lower(irFunction: IrFunction) { - val transformer = TypeOperatorTransformer(context, irFunction.symbol) - irFunction.transformChildrenVoid(transformer) - } -} - - -private class TypeOperatorTransformer(val context: CommonBackendContext, val function: IrFunctionSymbol) : IrElementTransformerVoid() { - - private val builder = context.createIrBuilder(function) - - val throwNullPointerException = context.ir.symbols.throwNullPointerException - - override fun visitFunction(declaration: IrFunction): IrStatement { - // ignore inner functions during this pass - return declaration +internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLoweringPass, IrBuildingTransformer(context) { + override fun lower(irFile: IrFile) { + irFile.transformChildren(this, null) } private fun IrType.erasure(): IrType { if (this !is IrSimpleType) return this - val classifier = this.classifier - return when (classifier) { + return when (val classifier = classifier) { is IrClassSymbol -> this is IrTypeParameterSymbol -> { val upperBound = classifier.owner.superTypes.firstOrNull() ?: @@ -87,7 +62,7 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun expression.argument.type.isSubtypeOf(typeOperand) -> expression.argument expression.argument.type.containsNull() -> { - with (builder) { + with(builder) { irLetS(expression.argument) { argument -> irIfThenElse( type = expression.type, @@ -96,7 +71,7 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun thenPart = if (typeOperand.isSimpleTypeWithQuestionMark) irNull() else - irCall(throwNullPointerException.owner), + irCall(this@TypeOperatorLowering.context.ir.symbols.throwNullPointerException.owner), elsePart = irAs(irGet(argument.owner), typeOperand.makeNotNull()) ) @@ -112,8 +87,6 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun } } - private fun KotlinType.isNullable() = TypeUtils.isNullableType(this) - private fun lowerSafeCast(expression: IrTypeOperatorCall): IrExpression { val typeOperand = expression.typeOperand.erasure() @@ -136,4 +109,4 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun else -> expression } } -} \ No newline at end of file +}