PSI2IR / FIR2IR: do not create temporaries for adapted references
Arguments to function references behave the same as arguments to function calls and should be evaluated once regardless, so the temporary is unnecessary.
This commit is contained in:
+4
-11
@@ -154,22 +154,15 @@ internal class AdapterGenerator(
|
||||
if (boundReceiver == null) {
|
||||
IrFunctionExpressionImpl(startOffset, endOffset, type, irAdapterFunction, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE)
|
||||
} else {
|
||||
// TODO add a bound receiver property to IrFunctionExpressionImpl?
|
||||
val irAdapterRef = IrFunctionReferenceImpl(
|
||||
startOffset, endOffset, type, irAdapterFunction.symbol, irAdapterFunction.typeParameters.size,
|
||||
irAdapterFunction.valueParameters.size, null, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
|
||||
)
|
||||
val statements = SmartList<IrStatement>()
|
||||
if (boundReceiver.isSafeToUseWithoutCopying()) {
|
||||
irAdapterRef.extensionReceiver = boundReceiver
|
||||
} else {
|
||||
val (irVariable, irVariableSymbol) = createTemporaryVariable(boundReceiver.deepCopyWithSymbols(), conversionScope)
|
||||
irAdapterRef.extensionReceiver = IrGetValueImpl(startOffset, endOffset, irVariableSymbol)
|
||||
statements.add(irVariable)
|
||||
IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE).apply {
|
||||
statements.add(irAdapterFunction)
|
||||
statements.add(irAdapterRef.apply { extensionReceiver = boundReceiver })
|
||||
}
|
||||
statements.add(irAdapterFunction)
|
||||
statements.add(irAdapterRef)
|
||||
|
||||
IrBlockImpl(startOffset, endOffset, type, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE, statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-17
@@ -153,35 +153,26 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
||||
resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||
isSafe = false
|
||||
).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val irAdapterRef = IrFunctionReferenceImpl(
|
||||
startOffset, endOffset, irFunctionalType, irAdapterFun.symbol, irAdapterFun.typeParameters.size,
|
||||
irAdapterFun.valueParameters.size, null, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
|
||||
)
|
||||
|
||||
val irDispatchReceiver = dispatchReceiverValue?.loadIfExists()
|
||||
val irExtensionReceiver = extensionReceiverValue?.loadIfExists()
|
||||
check(irDispatchReceiver == null || irExtensionReceiver == null) {
|
||||
"Bound callable reference cannot have both receivers: $adapteeDescriptor"
|
||||
}
|
||||
val receiver = irDispatchReceiver ?: irExtensionReceiver
|
||||
|
||||
if (receiver == null) {
|
||||
IrFunctionExpressionImpl(
|
||||
startOffset, endOffset, irFunctionalType, irAdapterFun, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
|
||||
)
|
||||
} else {
|
||||
val statements = SmartList<IrStatement>()
|
||||
if (receiver.isSafeToUseWithoutCopying()) {
|
||||
irAdapterRef.extensionReceiver = receiver
|
||||
} else {
|
||||
val irVariable = statementGenerator.scope.createTemporaryVariable(receiver, "receiver")
|
||||
irAdapterRef.extensionReceiver = IrGetValueImpl(startOffset, endOffset, irVariable.symbol)
|
||||
statements.add(irVariable)
|
||||
// TODO add a bound receiver property to IrFunctionExpressionImpl?
|
||||
val irAdapterRef = IrFunctionReferenceImpl(
|
||||
startOffset, endOffset, irFunctionalType, irAdapterFun.symbol, irAdapterFun.typeParameters.size,
|
||||
irAdapterFun.valueParameters.size, null, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE
|
||||
)
|
||||
IrBlockImpl(startOffset, endOffset, irFunctionalType, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE).apply {
|
||||
statements.add(irAdapterFun)
|
||||
statements.add(irAdapterRef.apply { extensionReceiver = receiver })
|
||||
}
|
||||
statements.add(irAdapterFun)
|
||||
statements.add(irAdapterRef)
|
||||
|
||||
IrBlockImpl(startOffset, endOffset, irFunctionalType, IrStatementOrigin.ADAPTED_FUNCTION_REFERENCE, statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,12 +529,6 @@ val IrDeclaration.isFileClass: Boolean
|
||||
val IrValueDeclaration.isImmutable: Boolean
|
||||
get() = this is IrValueParameter || this is IrVariable && !isVar
|
||||
|
||||
fun IrExpression.isSafeToUseWithoutCopying() =
|
||||
this is IrGetObjectValue ||
|
||||
this is IrGetEnumValue ||
|
||||
this is IrConst<*> ||
|
||||
this is IrGetValue && symbol.isBound && symbol.owner.isImmutable
|
||||
|
||||
val IrStatementOrigin?.isLambda: Boolean
|
||||
get() = this == IrStatementOrigin.LAMBDA || this == IrStatementOrigin.ANONYMOUS_FUNCTION
|
||||
|
||||
|
||||
Vendored
+1
-3
@@ -100,8 +100,6 @@ FILE fqName:<root> fileName:/constructorWithAdaptedArguments.kt
|
||||
RETURN type=kotlin.Nothing from='public final fun testInnerClassConstructorCapturingOuter (): kotlin.Any declared in <root>'
|
||||
CALL 'public final fun use (fn: kotlin.Function1<kotlin.Int, kotlin.Any>): kotlin.Any declared in <root>' type=kotlin.Any origin=null
|
||||
fn: BLOCK type=kotlin.Function1<kotlin.Int, <root>.Outer.Inner> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.Outer [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Outer' type=<root>.Outer origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:<init> visibility:local modality:FINAL <> ($receiver:<root>.Outer, p0:kotlin.Int) returnType:<root>.Outer.Inner
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.Outer
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -112,4 +110,4 @@ FILE fqName:<root> fileName:/constructorWithAdaptedArguments.kt
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'p0: kotlin.Int declared in <root>.testInnerClassConstructorCapturingOuter.<init>' type=kotlin.Int origin=null
|
||||
FUNCTION_REFERENCE 'local final fun <init> (p0: kotlin.Int): <root>.Outer.Inner declared in <root>.testInnerClassConstructorCapturingOuter' type=kotlin.Function1<kotlin.Int, <root>.Outer.Inner> origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null
|
||||
$receiver: GET_VAR 'val tmp_0: <root>.Outer [val] declared in <root>.testInnerClassConstructorCapturingOuter' type=<root>.Outer origin=null
|
||||
$receiver: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Outer' type=<root>.Outer origin=null
|
||||
|
||||
-2
@@ -108,8 +108,6 @@ FILE fqName:<root> fileName:/suspendConversion.kt
|
||||
BLOCK_BODY
|
||||
CALL 'public final fun useSuspend (fn: kotlin.coroutines.SuspendFunction0<kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.C [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:bar visibility:local modality:FINAL <> ($receiver:<root>.C) returnType:kotlin.Unit [suspend]
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.C
|
||||
BLOCK_BODY
|
||||
|
||||
+1
-3
@@ -109,12 +109,10 @@ FILE fqName:<root> fileName:/suspendConversion.kt
|
||||
BLOCK_BODY
|
||||
CALL 'public final fun useSuspend (fn: kotlin.coroutines.SuspendFunction0<kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.C [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:bar visibility:local modality:FINAL <> ($receiver:<root>.C) returnType:kotlin.Unit [suspend]
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.C
|
||||
BLOCK_BODY
|
||||
CALL 'public final fun bar (): kotlin.Unit declared in <root>.C' type=kotlin.Unit origin=null
|
||||
$this: GET_VAR 'receiver: <root>.C declared in <root>.testWithBoundReceiver.bar' type=<root>.C origin=ADAPTED_FUNCTION_REFERENCE
|
||||
FUNCTION_REFERENCE 'local final fun bar (): kotlin.Unit [suspend] declared in <root>.testWithBoundReceiver' type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null
|
||||
$receiver: GET_VAR 'val tmp_0: <root>.C [val] declared in <root>.testWithBoundReceiver' type=<root>.C origin=null
|
||||
$receiver: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.C' type=<root>.C origin=null
|
||||
|
||||
compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.fir.txt
Vendored
-4
@@ -55,8 +55,6 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Host' type=<root>.Host origin=null
|
||||
CALL 'public final fun use (fn: kotlin.Function1<kotlin.Int, kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.Host [val]
|
||||
GET_VAR 'var h: <root>.Host [var] declared in <root>.Host.testBoundReceiverLocalVar' type=<root>.Host origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:<root>.Host, p0:kotlin.Int) returnType:kotlin.Unit
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.Host
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -88,8 +86,6 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
BLOCK_BODY
|
||||
CALL 'public final fun use (fn: kotlin.Function1<kotlin.Int, kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:<root>.Host [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Host' type=<root>.Host origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:<root>.Host, p0:kotlin.Int) returnType:kotlin.Unit
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.Host
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
|
||||
Vendored
+2
-6
@@ -58,8 +58,6 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Host' type=<root>.Host origin=null
|
||||
CALL 'public final fun use (fn: kotlin.Function1<kotlin.Int, kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:<root>.Host [val]
|
||||
GET_VAR 'var h: <root>.Host [var] declared in <root>.Host.testBoundReceiverLocalVar' type=<root>.Host origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:<root>.Host, p0:kotlin.Int) returnType:kotlin.Unit
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.Host
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -70,7 +68,7 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'p0: kotlin.Int declared in <root>.Host.testBoundReceiverLocalVar.withVararg' type=kotlin.Int origin=null
|
||||
FUNCTION_REFERENCE 'local final fun withVararg (p0: kotlin.Int): kotlin.Unit declared in <root>.Host.testBoundReceiverLocalVar' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null
|
||||
$receiver: GET_VAR 'val tmp_0: <root>.Host [val] declared in <root>.Host.testBoundReceiverLocalVar' type=<root>.Host origin=null
|
||||
$receiver: GET_VAR 'var h: <root>.Host [var] declared in <root>.Host.testBoundReceiverLocalVar' type=<root>.Host origin=null
|
||||
FUN name:testBoundReceiverParameter visibility:public modality:FINAL <> ($this:<root>.Host, h:<root>.Host) returnType:kotlin.Unit
|
||||
$this: VALUE_PARAMETER name:<this> type:<root>.Host
|
||||
VALUE_PARAMETER name:h index:0 type:<root>.Host
|
||||
@@ -93,8 +91,6 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
BLOCK_BODY
|
||||
CALL 'public final fun use (fn: kotlin.Function1<kotlin.Int, kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||
fn: BLOCK type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:<root>.Host [val]
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Host' type=<root>.Host origin=null
|
||||
FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:<root>.Host, p0:kotlin.Int) returnType:kotlin.Unit
|
||||
$receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:<root>.Host
|
||||
VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int
|
||||
@@ -105,7 +101,7 @@ FILE fqName:<root> fileName:/withArgumentAdaptationAndReceiver.kt
|
||||
xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int
|
||||
GET_VAR 'p0: kotlin.Int declared in <root>.Host.testBoundReceiverExpression.withVararg' type=kotlin.Int origin=null
|
||||
FUNCTION_REFERENCE 'local final fun withVararg (p0: kotlin.Int): kotlin.Unit declared in <root>.Host.testBoundReceiverExpression' type=kotlin.Function1<kotlin.Int, kotlin.Unit> origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null
|
||||
$receiver: GET_VAR 'val tmp_1: <root>.Host [val] declared in <root>.Host.testBoundReceiverExpression' type=<root>.Host origin=null
|
||||
$receiver: CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.Host' type=<root>.Host origin=null
|
||||
FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator]
|
||||
overridden:
|
||||
public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any
|
||||
|
||||
Reference in New Issue
Block a user