JVM_IR: generate flags for adapted function references
This commit is contained in:
+55
-16
@@ -124,24 +124,33 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
private val useOptimizedSuperClass =
|
private val useOptimizedSuperClass =
|
||||||
context.state.generateOptimizedCallableReferenceSuperClasses
|
context.state.generateOptimizedCallableReferenceSuperClasses
|
||||||
|
|
||||||
private val adaptedReferenceOriginalTarget = if (callee.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
|
private val adaptedReferenceOriginalTarget: IrFunction?
|
||||||
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
|
private val adapteeCall: IrFunctionAccessExpression?
|
||||||
// applied to a call. That call's target is the original function which we need to get owner/name/signature.
|
|
||||||
val call = when (val statement = callee.body!!.statements.single()) {
|
init {
|
||||||
is IrTypeOperatorCall -> {
|
if (callee.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
|
||||||
assert(statement.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
|
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
|
||||||
"Unexpected type operator in ADAPTER_FOR_CALLABLE_REFERENCE: ${callee.render()}"
|
// applied to a call. That call's target is the original function which we need to get owner/name/signature.
|
||||||
|
val call = when (val statement = callee.body!!.statements.single()) {
|
||||||
|
is IrTypeOperatorCall -> {
|
||||||
|
assert(statement.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT) {
|
||||||
|
"Unexpected type operator in ADAPTER_FOR_CALLABLE_REFERENCE: ${callee.render()}"
|
||||||
|
}
|
||||||
|
statement.argument
|
||||||
}
|
}
|
||||||
statement.argument
|
is IrReturn -> statement.value
|
||||||
|
else -> statement
|
||||||
}
|
}
|
||||||
is IrReturn -> statement.value
|
if (call !is IrFunctionAccessExpression) {
|
||||||
else -> statement
|
throw UnsupportedOperationException("Unknown structure of ADAPTER_FOR_CALLABLE_REFERENCE: ${callee.render()}")
|
||||||
|
}
|
||||||
|
adapteeCall = call
|
||||||
|
adaptedReferenceOriginalTarget = call.symbol.owner
|
||||||
|
} else {
|
||||||
|
adapteeCall = null
|
||||||
|
adaptedReferenceOriginalTarget = null
|
||||||
}
|
}
|
||||||
if (call !is IrFunctionAccessExpression) {
|
}
|
||||||
throw UnsupportedOperationException("Unknown structure of ADAPTER_FOR_CALLABLE_REFERENCE: ${callee.render()}")
|
|
||||||
}
|
|
||||||
call.symbol.owner
|
|
||||||
} else null
|
|
||||||
|
|
||||||
private val superType =
|
private val superType =
|
||||||
samSuperType ?: when {
|
samSuperType ?: when {
|
||||||
@@ -269,7 +278,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
putValueArgument(index++, generateSignature(callableReferenceTarget.symbol))
|
putValueArgument(index++, generateSignature(callableReferenceTarget.symbol))
|
||||||
putValueArgument(
|
putValueArgument(
|
||||||
index,
|
index,
|
||||||
irInt(if (callableReferenceTarget.parent.let { it is IrClass && it.isFileClass }) 1 else 0)
|
irInt(getFunctionReferenceFlags(callableReferenceTarget))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,6 +288,36 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getFunctionReferenceFlags(callableReferenceTarget: IrFunction): Int {
|
||||||
|
val isTopLevelBit = if (callableReferenceTarget.parent.let { it is IrClass && it.isFileClass }) 1 else 0
|
||||||
|
val adaptedCallableReferenceFlags = getAdaptedCallableReferenceFlags()
|
||||||
|
return isTopLevelBit + (adaptedCallableReferenceFlags shl 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAdaptedCallableReferenceFlags(): Int {
|
||||||
|
if (adaptedReferenceOriginalTarget == null) return 0
|
||||||
|
|
||||||
|
val isVarargMappedToElementBit = if (hasVarargMappedToElement()) 1 else 0
|
||||||
|
val isSuspendConvertedBit = if (!adaptedReferenceOriginalTarget.isSuspend && callee.isSuspend) 1 else 0
|
||||||
|
val isCoercedToUnitBit = if (!adaptedReferenceOriginalTarget.returnType.isUnit() && callee.returnType.isUnit()) 1 else 0
|
||||||
|
|
||||||
|
return isVarargMappedToElementBit +
|
||||||
|
(isSuspendConvertedBit shl 1) +
|
||||||
|
(isCoercedToUnitBit shl 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasVarargMappedToElement(): Boolean {
|
||||||
|
if (adapteeCall == null) return false
|
||||||
|
for (i in 0 until adapteeCall.valueArgumentsCount) {
|
||||||
|
val arg = adapteeCall.getValueArgument(i) ?: continue
|
||||||
|
if (arg !is IrVararg) continue
|
||||||
|
for (varargElement in arg.elements) {
|
||||||
|
if (varargElement is IrGetValue) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction =
|
private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction =
|
||||||
functionReferenceClass.addFunction {
|
functionReferenceClass.addFunction {
|
||||||
setSourceRange(if (isLambda) callee else irFunctionReference)
|
setSourceRange(if (isLambda) callee else irFunctionReference)
|
||||||
|
|||||||
+3
@@ -16,6 +16,7 @@ fun target(x: Int, y: String = "", z: String = ""): Int = x
|
|||||||
fun captureNoDefaults(fn: (Int, String, String) -> Unit): Any = fn
|
fun captureNoDefaults(fn: (Int, String, String) -> Unit): Any = fn
|
||||||
fun captureOneDefault(fn: (Int, String) -> Unit): Any = fn
|
fun captureOneDefault(fn: (Int, String) -> Unit): Any = fn
|
||||||
fun captureAllDefaults(fn: (Int) -> Unit): Any = fn
|
fun captureAllDefaults(fn: (Int) -> Unit): Any = fn
|
||||||
|
fun captureOneDefaultWithoutCoercionToUnit(fn: (Int, String) -> Int): Any = fn
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
checkEqual(captureNoDefaults(::target), captureNoDefaults(::target))
|
checkEqual(captureNoDefaults(::target), captureNoDefaults(::target))
|
||||||
@@ -26,6 +27,8 @@ fun box(): String {
|
|||||||
checkNotEqual(captureNoDefaults(::target), captureOneDefault(::target))
|
checkNotEqual(captureNoDefaults(::target), captureOneDefault(::target))
|
||||||
checkNotEqual(captureNoDefaults(::target), captureAllDefaults(::target))
|
checkNotEqual(captureNoDefaults(::target), captureAllDefaults(::target))
|
||||||
|
|
||||||
|
checkNotEqual(captureOneDefault(::target), captureOneDefaultWithoutCoercionToUnit(::target))
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
@@ -16,6 +16,9 @@ fun target(x: Int, vararg ys: String): Int = x + ys.size
|
|||||||
fun captureVararg1(fn: (Int, String) -> Unit): Any = fn
|
fun captureVararg1(fn: (Int, String) -> Unit): Any = fn
|
||||||
fun captureVararg0(fn: (Int) -> Unit): Any = fn
|
fun captureVararg0(fn: (Int) -> Unit): Any = fn
|
||||||
|
|
||||||
|
fun captureNoVararg(fn: (Int, Array<String>) -> Int): Any = fn
|
||||||
|
fun captureNoVarargCoerced(fn: (Int, Array<String>) -> Unit): Any = fn
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
checkEqual(captureVararg1(::target), captureVararg1(::target))
|
checkEqual(captureVararg1(::target), captureVararg1(::target))
|
||||||
checkEqual(captureVararg0(::target), captureVararg0(::target))
|
checkEqual(captureVararg0(::target), captureVararg0(::target))
|
||||||
@@ -23,6 +26,8 @@ fun box(): String {
|
|||||||
|
|
||||||
checkNotEqual(captureVararg1(::target), captureVararg0(::target))
|
checkNotEqual(captureVararg1(::target), captureVararg0(::target))
|
||||||
|
|
||||||
|
checkNotEqual(captureNoVararg(::target), captureNoVarargCoerced(::target))
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// !LANGUAGE: +SuspendConversion
|
// !LANGUAGE: +SuspendConversion
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
// IGNORE_BACKEND: JVM_IR, JS_IR
|
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||||
|
// ^ TODO fix suspend coercion for bound function references in JVM_IR
|
||||||
// FILE: suspendCovnersion.kt
|
// FILE: suspendCovnersion.kt
|
||||||
|
|
||||||
fun checkNotEqual(x: Any, y: Any) {
|
fun checkNotEqual(x: Any, y: Any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user