backend: improve type operators support:
* add initial support for casts with generics;
* optimize out the casts to subtypes
Also add tests unchecked_cast{1,2}, the latter is disabled.
This commit is contained in:
committed by
SvyatoslavScherbina
parent
9bf0380048
commit
65444ec690
+14
-14
@@ -18,28 +18,28 @@ import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns)
|
||||
|
||||
class FunctionIrGenerator(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) : IrGeneratorWithScope {
|
||||
override val context = IrLoweringContext(backendContext)
|
||||
override val scope = Scope(functionDescriptor)
|
||||
}
|
||||
class FunctionIrBuilder(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) :
|
||||
IrBuilderWithScope(
|
||||
IrLoweringContext(backendContext),
|
||||
Scope(functionDescriptor),
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET
|
||||
)
|
||||
|
||||
fun BackendContext.createFunctionIrGenerator(functionDescriptor: FunctionDescriptor) =
|
||||
FunctionIrGenerator(this, functionDescriptor)
|
||||
fun BackendContext.createFunctionIrBuilder(functionDescriptor: FunctionDescriptor) =
|
||||
FunctionIrBuilder(this, functionDescriptor)
|
||||
|
||||
class FunctionIrBuilder(context: IrLoweringContext, scope: Scope, startOffset: Int, endOffset: Int) :
|
||||
IrBuilderWithScope(context, scope, startOffset, endOffset)
|
||||
|
||||
fun FunctionIrGenerator.createIrBuilder() = FunctionIrBuilder(context, scope, UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
fun <T : IrBuilder> T.at(element: IrElement) = this.at(element.startOffset, element.endOffset)
|
||||
|
||||
/**
|
||||
* Builds [IrBlock] to be used instead of given expression.
|
||||
*/
|
||||
inline fun FunctionIrGenerator.irBlock(expression: IrExpression, origin: IrStatementOrigin? = null,
|
||||
resultType: KotlinType? = expression.type,
|
||||
body: IrBlockBuilder.() -> Unit) =
|
||||
inline fun IrGeneratorWithScope.irBlock(expression: IrExpression, origin: IrStatementOrigin? = null,
|
||||
resultType: KotlinType? = expression.type,
|
||||
body: IrBlockBuilder.() -> Unit) =
|
||||
this.irBlock(expression.startOffset, expression.endOffset, origin, resultType, body)
|
||||
|
||||
inline fun FunctionIrGenerator.irBlockBody(irElement: IrElement, body: IrBlockBodyBuilder.() -> Unit) =
|
||||
inline fun IrGeneratorWithScope.irBlockBody(irElement: IrElement, body: IrBlockBodyBuilder.() -> Unit) =
|
||||
this.irBlockBody(irElement.startOffset, irElement.endOffset, body)
|
||||
|
||||
fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<CallableMemberDescriptor>): List<DeclarationDescriptor> {
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
@@ -136,8 +136,8 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
|
||||
// Create new function descriptor:
|
||||
val newDescriptor = createSimpleFunctionImplTargetDescriptor(descriptor, unboundParams)
|
||||
|
||||
val generator = lower.context.createFunctionIrGenerator(newDescriptor)
|
||||
val blockBody = generator.irBlockBody(startOffset, endOffset) {
|
||||
val builder = lower.context.createFunctionIrBuilder(newDescriptor)
|
||||
val blockBody = builder.irBlockBody(startOffset, endOffset) {
|
||||
val boundArgsGet = irCall(simpleFunctionImplBoundArgsGetter).apply {
|
||||
dispatchReceiver = irGet(newDescriptor.valueParameters[0])
|
||||
}
|
||||
|
||||
+5
-10
@@ -2,8 +2,8 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
@@ -61,14 +61,9 @@ class DefaultParameterStubGenerator internal constructor(val context: Context):
|
||||
|
||||
val functionDescriptor = irFunction.descriptor
|
||||
if (bodies.isNotEmpty()) {
|
||||
val (descriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
|
||||
val generator = context.createFunctionIrGenerator(descriptor)
|
||||
val builder = generator.createIrBuilder()
|
||||
builder.apply {
|
||||
startOffset = irFunction.startOffset
|
||||
endOffset = irFunction.endOffset
|
||||
}
|
||||
val body = generator.irBlockBody {
|
||||
val (descriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
|
||||
val builder = context.createFunctionIrBuilder(descriptor)
|
||||
val body = builder.irBlockBody(irFunction) {
|
||||
val params = mutableListOf<VariableDescriptor>()
|
||||
val variables = mutableMapOf<VariableDescriptor, VariableDescriptor>()
|
||||
|
||||
|
||||
+35
-6
@@ -1,10 +1,10 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
/**
|
||||
* This lowering pass lowers some [IrTypeOperatorCall]s.
|
||||
@@ -27,19 +29,45 @@ internal class TypeOperatorLowering(val context: Context) : FunctionLoweringPass
|
||||
|
||||
private class TypeOperatorTransformer(val context: Context, val function: FunctionDescriptor) : IrElementTransformerVoid() {
|
||||
|
||||
private val generator = context.createFunctionIrGenerator(function)
|
||||
private val builder = context.createFunctionIrBuilder(function)
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
// ignore inner functions during this pass
|
||||
return declaration
|
||||
}
|
||||
|
||||
private tailrec fun KotlinType.erasure(): KotlinType {
|
||||
val descriptor = this.constructor.declarationDescriptor
|
||||
return if (descriptor is TypeParameterDescriptor) {
|
||||
val upperBound = descriptor.upperBounds.singleOrNull() ?:
|
||||
TODO("$descriptor : ${descriptor.upperBounds}")
|
||||
|
||||
upperBound.erasure()
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerCast(expression: IrTypeOperatorCall): IrExpression {
|
||||
val typeOperand = expression.typeOperand.erasure()
|
||||
return if (expression.argument.type.isSubtypeOf(typeOperand)) {
|
||||
// TODO: consider the case when expression type is wrong e.g. due to generics-related unchecked casts.
|
||||
expression.argument
|
||||
} else if (typeOperand == expression.typeOperand) {
|
||||
expression
|
||||
} else {
|
||||
builder.at(expression).irAs(expression.argument, typeOperand)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerSafeCast(expression: IrTypeOperatorCall): IrExpression {
|
||||
return generator.irBlock(expression) {
|
||||
val typeOperand = expression.typeOperand.erasure()
|
||||
|
||||
return builder.irBlock(expression) {
|
||||
+irLet(expression.argument) { variable ->
|
||||
irIfThenElse(expression.type,
|
||||
condition = irIs(irGet(variable), expression.typeOperand),
|
||||
thenPart = irImplicitCast(irGet(variable), expression.typeOperand),
|
||||
condition = irIs(irGet(variable), typeOperand),
|
||||
thenPart = irImplicitCast(irGet(variable), typeOperand),
|
||||
elsePart = irNull())
|
||||
}
|
||||
}
|
||||
@@ -50,6 +78,7 @@ private class TypeOperatorTransformer(val context: Context, val function: Functi
|
||||
|
||||
return when (expression.operator) {
|
||||
IrTypeOperator.SAFE_CAST -> lowerSafeCast(expression)
|
||||
IrTypeOperator.CAST -> lowerCast(expression)
|
||||
else -> expression
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +208,17 @@ task cast_simple(type: RunKonanTest) {
|
||||
source = "codegen/basics/cast_simple.kt"
|
||||
}
|
||||
|
||||
task unchecked_cast1(type: RunKonanTest) {
|
||||
goldValue = "17\n17\n42\n42\n"
|
||||
source = "codegen/basics/unchecked_cast1.kt"
|
||||
}
|
||||
|
||||
task unchecked_cast2(type: RunKonanTest) {
|
||||
disabled = true
|
||||
goldValue = "Ok\n"
|
||||
source = "codegen/basics/unchecked_cast2.kt"
|
||||
}
|
||||
|
||||
task null_check(type: RunKonanTest) {
|
||||
source = "codegen/basics/null_check.kt"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
fun main(args: Array<String>) {
|
||||
foo<String>("17")
|
||||
bar<String>("17")
|
||||
foo<String>(42)
|
||||
bar<String>(42)
|
||||
}
|
||||
|
||||
fun <T> foo(x: Any?) {
|
||||
val y = x as T
|
||||
println(y.toString())
|
||||
}
|
||||
|
||||
fun <T> bar(x: Any?) {
|
||||
val y = x as? T
|
||||
println(y.toString())
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fun main(args: Array<String>) {
|
||||
try {
|
||||
val x = cast<String>(Any())
|
||||
println(x.length)
|
||||
} catch (e: Throwable) {
|
||||
println("Ok")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> cast(x: Any?) = x as T
|
||||
Reference in New Issue
Block a user