FIR2IR: Imitate K1 behavior when SAM type has a bit different shape
See the relevant test at t/
estData/codegen/box/sam/contravariantIntersectionType.kt
After the previous commit, when generating a call for `doOnSuccess {}`,
we have a SAM type with removed projection Consumer<Any?>, while
real function type of the lambda is a bit different
(Function1<ConcreteType & ConcreteType2>).
While for me, that looks questionable, but in K1 it was effectively
resolved via the same implicit cast that on JVM is generated to an
INVOKEDYNAMIC that wraps initial function-typed value.
^KT-53552 Fixed
This commit is contained in:
committed by
Space Team
parent
05ca001310
commit
99448b77f3
+20
-1
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
|||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi2ir.generators.implicitCastTo
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.model.TypeVariance
|
import org.jetbrains.kotlin.types.model.TypeVariance
|
||||||
@@ -443,7 +444,25 @@ internal class AdapterGenerator(
|
|||||||
val samType = samFirType.toIrType(ConversionTypeContext.DEFAULT)
|
val samType = samFirType.toIrType(ConversionTypeContext.DEFAULT)
|
||||||
// Make sure the converted IrType owner indeed has a single abstract method, since FunctionReferenceLowering relies on it.
|
// Make sure the converted IrType owner indeed has a single abstract method, since FunctionReferenceLowering relies on it.
|
||||||
if (!samType.isSamType) return this
|
if (!samType.isSamType) return this
|
||||||
return IrTypeOperatorCallImpl(this.startOffset, this.endOffset, samType, IrTypeOperator.SAM_CONVERSION, samType, this)
|
return IrTypeOperatorCallImpl(
|
||||||
|
this.startOffset, this.endOffset, samType, IrTypeOperator.SAM_CONVERSION, samType,
|
||||||
|
castArgumentToFunctionalInterfaceForSamType(this, argument.typeRef.coneType, samFirType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See org.jetbrains.kotlin.psi2ir.generators.ArgumentsGenerationUtilsKt.castArgumentToFunctionalInterfaceForSamType (K1 counterpart)
|
||||||
|
private fun castArgumentToFunctionalInterfaceForSamType(
|
||||||
|
argument: IrExpression,
|
||||||
|
argumentConeType: ConeKotlinType,
|
||||||
|
samType: ConeKotlinType
|
||||||
|
): IrExpression {
|
||||||
|
val coneKotlinFunctionType = getFunctionTypeForPossibleSamType(samType) ?: return argument
|
||||||
|
// This line is not present in the K1 counterpart because there is InsertImplicitCasts::cast that effectively removes
|
||||||
|
// such unnecessary casts. At the same time, many IR lowerings assume that there are no such redundant casts and many
|
||||||
|
// tests from FirBlackBoxCodegenTestGenerated relevant to INDY start failing once this line is removed.
|
||||||
|
if (argumentConeType.isSubtypeOf(coneKotlinFunctionType, session)) return argument
|
||||||
|
val irFunctionType = coneKotlinFunctionType.toIrType()
|
||||||
|
return argument.implicitCastTo(irFunctionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is mostly a mirror of org.jetbrains.kotlin.backend.common.SamTypeApproximator.removeExternalProjections
|
// This function is mostly a mirror of org.jetbrains.kotlin.backend.common.SamTypeApproximator.removeExternalProjections
|
||||||
|
|||||||
Vendored
+27
-24
@@ -32,33 +32,36 @@ FILE fqName:<root> fileName:/chainedFunSuspendConversionForSimpleExpression.kt
|
|||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||||
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
||||||
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
||||||
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
||||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
||||||
BLOCK_BODY
|
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
||||||
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
BLOCK_BODY
|
||||||
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
||||||
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
$receiver: GET_VAR 'f: kotlin.Function0<kotlin.Unit> declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
||||||
|
$receiver: GET_VAR 'f: kotlin.Function0<kotlin.Unit> declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||||
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
||||||
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
||||||
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
||||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
||||||
BLOCK_BODY
|
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
||||||
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
BLOCK_BODY
|
||||||
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
||||||
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
$receiver: CALL 'public final fun bar (): kotlin.Function0<kotlin.Unit> declared in <root>' type=kotlin.Function0<kotlin.Unit> origin=null
|
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
||||||
|
$receiver: CALL 'public final fun bar (): kotlin.Function0<kotlin.Unit> declared in <root>' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
VAR name:t type:kotlin.Function0<kotlin.Unit> [var]
|
VAR name:t type:kotlin.Function0<kotlin.Unit> [var]
|
||||||
GET_VAR 'f: kotlin.Function0<kotlin.Unit> declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
GET_VAR 'f: kotlin.Function0<kotlin.Unit> declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
CALL 'public final fun foo (s: <root>.SuspendRunnable): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||||
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
s: TYPE_OP type=<root>.SuspendRunnable origin=SAM_CONVERSION typeOperand=<root>.SuspendRunnable
|
||||||
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
||||||
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION
|
||||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
FUN ADAPTER_FOR_SUSPEND_CONVERSION name:suspendConversion visibility:local modality:FINAL <> ($receiver:kotlin.Function0<kotlin.Unit>) returnType:kotlin.Unit [suspend]
|
||||||
BLOCK_BODY
|
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_SUSPEND_CONVERSION name:callee type:kotlin.Function0<kotlin.Unit>
|
||||||
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
BLOCK_BODY
|
||||||
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=kotlin.Unit origin=null
|
||||||
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
$this: GET_VAR 'callee: kotlin.Function0<kotlin.Unit> declared in <root>.test.suspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
$receiver: GET_VAR 'var t: kotlin.Function0<kotlin.Unit> [var] declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
FUNCTION_REFERENCE 'local final fun suspendConversion (): kotlin.Unit [suspend] declared in <root>.test' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=SUSPEND_CONVERSION reflectionTarget=null
|
||||||
|
$receiver: GET_VAR 'var t: kotlin.Function0<kotlin.Unit> [var] declared in <root>.test' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ FILE fqName:<root> fileName:/test.kt
|
|||||||
$this: GET_VAR 'val map: kotlin.collections.MutableMap<<root>.Fun, kotlin.String> [val] declared in <root>.box' type=kotlin.collections.MutableMap<<root>.Fun, kotlin.String> origin=null
|
$this: GET_VAR 'val map: kotlin.collections.MutableMap<<root>.Fun, kotlin.String> [val] declared in <root>.box' type=kotlin.collections.MutableMap<<root>.Fun, kotlin.String> origin=null
|
||||||
p0: GET_VAR 'val fn: <root>.Fun [val] declared in <root>.box' type=<root>.Fun origin=null
|
p0: GET_VAR 'val fn: <root>.Fun [val] declared in <root>.box' type=<root>.Fun origin=null
|
||||||
p1: TYPE_OP type=@[EnhancedNullability] java.util.function.Function<kotlin.Any?, @[EnhancedNullability] kotlin.String> origin=SAM_CONVERSION typeOperand=@[EnhancedNullability] java.util.function.Function<kotlin.Any?, @[EnhancedNullability] kotlin.String>
|
p1: TYPE_OP type=@[EnhancedNullability] java.util.function.Function<kotlin.Any?, @[EnhancedNullability] kotlin.String> origin=SAM_CONVERSION typeOperand=@[EnhancedNullability] java.util.function.Function<kotlin.Any?, @[EnhancedNullability] kotlin.String>
|
||||||
FUN_EXPR type=kotlin.Function1<@[EnhancedNullability] <root>.Fun, @[EnhancedNullability] kotlin.String> origin=LAMBDA
|
TYPE_OP type=kotlin.Function1<@[EnhancedNullability] kotlin.Any?, @[EnhancedNullability] kotlin.String> origin=IMPLICIT_CAST typeOperand=kotlin.Function1<@[EnhancedNullability] kotlin.Any?, @[EnhancedNullability] kotlin.String>
|
||||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:@[EnhancedNullability] <root>.Fun) returnType:@[EnhancedNullability] kotlin.String
|
FUN_EXPR type=kotlin.Function1<@[EnhancedNullability] <root>.Fun, @[EnhancedNullability] kotlin.String> origin=LAMBDA
|
||||||
VALUE_PARAMETER name:it index:0 type:@[EnhancedNullability] <root>.Fun
|
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> (it:@[EnhancedNullability] <root>.Fun) returnType:@[EnhancedNullability] kotlin.String
|
||||||
BLOCK_BODY
|
VALUE_PARAMETER name:it index:0 type:@[EnhancedNullability] <root>.Fun
|
||||||
RETURN type=kotlin.Nothing from='local final fun <anonymous> (it: @[EnhancedNullability] <root>.Fun): @[EnhancedNullability] kotlin.String declared in <root>.box'
|
BLOCK_BODY
|
||||||
CONST String type=kotlin.String value="OK"
|
RETURN type=kotlin.Nothing from='local final fun <anonymous> (it: @[EnhancedNullability] <root>.Fun): @[EnhancedNullability] kotlin.String declared in <root>.box'
|
||||||
|
CONST String type=kotlin.String value="OK"
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ fun box(): String {
|
|||||||
return map.computeIfAbsent(p0 = fn, p1 = local fun <anonymous>(it: @EnhancedNullability Fun): @EnhancedNullability String {
|
return map.computeIfAbsent(p0 = fn, p1 = local fun <anonymous>(it: @EnhancedNullability Fun): @EnhancedNullability String {
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
/*-> @EnhancedNullability Function<Any?, @EnhancedNullability String> */) /*!! String */
|
/*as Function1<@EnhancedNullability Any?, @EnhancedNullability String> */ /*-> @EnhancedNullability Function<Any?, @EnhancedNullability String> */) /*!! String */
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user