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)
This commit is contained in:
committed by
Vasily Levchenko
parent
306fd2ae07
commit
297361f0c8
+51
-48
@@ -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<IrFunction?> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-38
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user