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 =
|
||||
context.state.generateOptimizedCallableReferenceSuperClasses
|
||||
|
||||
private val adaptedReferenceOriginalTarget = if (callee.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
|
||||
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
|
||||
// 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()}"
|
||||
private val adaptedReferenceOriginalTarget: IrFunction?
|
||||
private val adapteeCall: IrFunctionAccessExpression?
|
||||
|
||||
init {
|
||||
if (callee.origin == IrDeclarationOrigin.ADAPTER_FOR_CALLABLE_REFERENCE) {
|
||||
// The body of a callable reference adapter contains either only a call, or an IMPLICIT_COERCION_TO_UNIT type operator
|
||||
// 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
|
||||
else -> statement
|
||||
if (call !is IrFunctionAccessExpression) {
|
||||
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 =
|
||||
samSuperType ?: when {
|
||||
@@ -269,7 +278,7 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
putValueArgument(index++, generateSignature(callableReferenceTarget.symbol))
|
||||
putValueArgument(
|
||||
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 =
|
||||
functionReferenceClass.addFunction {
|
||||
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 captureOneDefault(fn: (Int, String) -> Unit): Any = fn
|
||||
fun captureAllDefaults(fn: (Int) -> Unit): Any = fn
|
||||
fun captureOneDefaultWithoutCoercionToUnit(fn: (Int, String) -> Int): Any = fn
|
||||
|
||||
fun box(): String {
|
||||
checkEqual(captureNoDefaults(::target), captureNoDefaults(::target))
|
||||
@@ -26,6 +27,8 @@ fun box(): String {
|
||||
checkNotEqual(captureNoDefaults(::target), captureOneDefault(::target))
|
||||
checkNotEqual(captureNoDefaults(::target), captureAllDefaults(::target))
|
||||
|
||||
checkNotEqual(captureOneDefault(::target), captureOneDefaultWithoutCoercionToUnit(::target))
|
||||
|
||||
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 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 {
|
||||
checkEqual(captureVararg1(::target), captureVararg1(::target))
|
||||
checkEqual(captureVararg0(::target), captureVararg0(::target))
|
||||
@@ -23,6 +26,8 @@ fun box(): String {
|
||||
|
||||
checkNotEqual(captureVararg1(::target), captureVararg0(::target))
|
||||
|
||||
checkNotEqual(captureNoVararg(::target), captureNoVarargCoerced(::target))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +SuspendConversion
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR, JS_IR
|
||||
// ^ TODO fix suspend coercion for bound function references in JVM_IR
|
||||
// FILE: suspendCovnersion.kt
|
||||
|
||||
fun checkNotEqual(x: Any, y: Any) {
|
||||
|
||||
Reference in New Issue
Block a user