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 IrLoweringContext(backendContext: BackendContext) : IrGeneratorContext(backendContext.irBuiltIns)
|
||||||
|
|
||||||
class FunctionIrGenerator(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) : IrGeneratorWithScope {
|
class FunctionIrBuilder(backendContext: BackendContext, functionDescriptor: FunctionDescriptor) :
|
||||||
override val context = IrLoweringContext(backendContext)
|
IrBuilderWithScope(
|
||||||
override val scope = Scope(functionDescriptor)
|
IrLoweringContext(backendContext),
|
||||||
}
|
Scope(functionDescriptor),
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET
|
||||||
|
)
|
||||||
|
|
||||||
fun BackendContext.createFunctionIrGenerator(functionDescriptor: FunctionDescriptor) =
|
fun BackendContext.createFunctionIrBuilder(functionDescriptor: FunctionDescriptor) =
|
||||||
FunctionIrGenerator(this, functionDescriptor)
|
FunctionIrBuilder(this, functionDescriptor)
|
||||||
|
|
||||||
class FunctionIrBuilder(context: IrLoweringContext, scope: Scope, startOffset: Int, endOffset: Int) :
|
fun <T : IrBuilder> T.at(element: IrElement) = this.at(element.startOffset, element.endOffset)
|
||||||
IrBuilderWithScope(context, scope, startOffset, endOffset)
|
|
||||||
|
|
||||||
fun FunctionIrGenerator.createIrBuilder() = FunctionIrBuilder(context, scope, UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds [IrBlock] to be used instead of given expression.
|
* Builds [IrBlock] to be used instead of given expression.
|
||||||
*/
|
*/
|
||||||
inline fun FunctionIrGenerator.irBlock(expression: IrExpression, origin: IrStatementOrigin? = null,
|
inline fun IrGeneratorWithScope.irBlock(expression: IrExpression, origin: IrStatementOrigin? = null,
|
||||||
resultType: KotlinType? = expression.type,
|
resultType: KotlinType? = expression.type,
|
||||||
body: IrBlockBuilder.() -> Unit) =
|
body: IrBlockBuilder.() -> Unit) =
|
||||||
this.irBlock(expression.startOffset, expression.endOffset, origin, resultType, body)
|
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)
|
this.irBlockBody(irElement.startOffset, irElement.endOffset, body)
|
||||||
|
|
||||||
fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<CallableMemberDescriptor>): List<DeclarationDescriptor> {
|
fun computeOverrides(current: ClassDescriptor, functionsFromCurrent: List<CallableMemberDescriptor>): List<DeclarationDescriptor> {
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.lower
|
package org.jetbrains.kotlin.backend.konan.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
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.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||||
@@ -136,8 +136,8 @@ private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
|
|||||||
// Create new function descriptor:
|
// Create new function descriptor:
|
||||||
val newDescriptor = createSimpleFunctionImplTargetDescriptor(descriptor, unboundParams)
|
val newDescriptor = createSimpleFunctionImplTargetDescriptor(descriptor, unboundParams)
|
||||||
|
|
||||||
val generator = lower.context.createFunctionIrGenerator(newDescriptor)
|
val builder = lower.context.createFunctionIrBuilder(newDescriptor)
|
||||||
val blockBody = generator.irBlockBody(startOffset, endOffset) {
|
val blockBody = builder.irBlockBody(startOffset, endOffset) {
|
||||||
val boundArgsGet = irCall(simpleFunctionImplBoundArgsGetter).apply {
|
val boundArgsGet = irCall(simpleFunctionImplBoundArgsGetter).apply {
|
||||||
dispatchReceiver = irGet(newDescriptor.valueParameters[0])
|
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.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
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.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
@@ -61,14 +61,9 @@ class DefaultParameterStubGenerator internal constructor(val context: Context):
|
|||||||
|
|
||||||
val functionDescriptor = irFunction.descriptor
|
val functionDescriptor = irFunction.descriptor
|
||||||
if (bodies.isNotEmpty()) {
|
if (bodies.isNotEmpty()) {
|
||||||
val (descriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
|
val (descriptor, mask, extension, dispatch) = functionDescriptor.generateDefaultsDescriptor()
|
||||||
val generator = context.createFunctionIrGenerator(descriptor)
|
val builder = context.createFunctionIrBuilder(descriptor)
|
||||||
val builder = generator.createIrBuilder()
|
val body = builder.irBlockBody(irFunction) {
|
||||||
builder.apply {
|
|
||||||
startOffset = irFunction.startOffset
|
|
||||||
endOffset = irFunction.endOffset
|
|
||||||
}
|
|
||||||
val body = generator.irBlockBody {
|
|
||||||
val params = mutableListOf<VariableDescriptor>()
|
val params = mutableListOf<VariableDescriptor>()
|
||||||
val variables = mutableMapOf<VariableDescriptor, VariableDescriptor>()
|
val variables = mutableMapOf<VariableDescriptor, VariableDescriptor>()
|
||||||
|
|
||||||
|
|||||||
+35
-6
@@ -1,10 +1,10 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.lower
|
package org.jetbrains.kotlin.backend.konan.lower
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createFunctionIrGenerator
|
import org.jetbrains.kotlin.backend.common.lower.*
|
||||||
import org.jetbrains.kotlin.backend.common.lower.irBlock
|
|
||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
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.expressions.IrTypeOperatorCall
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
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.
|
* 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 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 {
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
// ignore inner functions during this pass
|
// ignore inner functions during this pass
|
||||||
return declaration
|
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 {
|
private fun lowerSafeCast(expression: IrTypeOperatorCall): IrExpression {
|
||||||
return generator.irBlock(expression) {
|
val typeOperand = expression.typeOperand.erasure()
|
||||||
|
|
||||||
|
return builder.irBlock(expression) {
|
||||||
+irLet(expression.argument) { variable ->
|
+irLet(expression.argument) { variable ->
|
||||||
irIfThenElse(expression.type,
|
irIfThenElse(expression.type,
|
||||||
condition = irIs(irGet(variable), expression.typeOperand),
|
condition = irIs(irGet(variable), typeOperand),
|
||||||
thenPart = irImplicitCast(irGet(variable), expression.typeOperand),
|
thenPart = irImplicitCast(irGet(variable), typeOperand),
|
||||||
elsePart = irNull())
|
elsePart = irNull())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,6 +78,7 @@ private class TypeOperatorTransformer(val context: Context, val function: Functi
|
|||||||
|
|
||||||
return when (expression.operator) {
|
return when (expression.operator) {
|
||||||
IrTypeOperator.SAFE_CAST -> lowerSafeCast(expression)
|
IrTypeOperator.SAFE_CAST -> lowerSafeCast(expression)
|
||||||
|
IrTypeOperator.CAST -> lowerCast(expression)
|
||||||
else -> expression
|
else -> expression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,17 @@ task cast_simple(type: RunKonanTest) {
|
|||||||
source = "codegen/basics/cast_simple.kt"
|
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) {
|
task null_check(type: RunKonanTest) {
|
||||||
source = "codegen/basics/null_check.kt"
|
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