From ccf921510d71e8476d0b631eb09dcf7b6a5d320c Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 6 Oct 2020 16:14:13 +0200 Subject: [PATCH] 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. --- .../backend/generators/AdapterGenerator.kt | 15 +++-------- .../ReflectionReferencesGenerator.kt | 25 ++++++------------- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 6 ----- .../constructorWithAdaptedArguments.txt | 4 +-- .../suspendConversion.fir.txt | 2 -- .../callableReferences/suspendConversion.txt | 4 +-- .../withArgumentAdaptationAndReceiver.fir.txt | 4 --- .../withArgumentAdaptationAndReceiver.txt | 8 ++---- 8 files changed, 16 insertions(+), 52 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt index 9ac4d69e0cd..3feaf6645df 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt @@ -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() - 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) } } } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt index beb3241b397..0d23ea2183c 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt @@ -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() - 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) } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 9ad2e34847d..cb63dd7e753 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -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 diff --git a/compiler/testData/ir/irText/expressions/callableReferences/constructorWithAdaptedArguments.txt b/compiler/testData/ir/irText/expressions/callableReferences/constructorWithAdaptedArguments.txt index 0db4400bbf5..82ebbb6d5a9 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/constructorWithAdaptedArguments.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/constructorWithAdaptedArguments.txt @@ -100,8 +100,6 @@ FILE fqName: fileName:/constructorWithAdaptedArguments.kt RETURN type=kotlin.Nothing from='public final fun testInnerClassConstructorCapturingOuter (): kotlin.Any declared in ' CALL 'public final fun use (fn: kotlin.Function1): kotlin.Any declared in ' type=kotlin.Any origin=null fn: BLOCK type=kotlin.Function1.Outer.Inner> origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.Outer [val] - CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Outer' type=.Outer origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name: visibility:local modality:FINAL <> ($receiver:.Outer, p0:kotlin.Int) returnType:.Outer.Inner $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.Outer VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int @@ -112,4 +110,4 @@ FILE fqName: fileName:/constructorWithAdaptedArguments.kt xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int GET_VAR 'p0: kotlin.Int declared in .testInnerClassConstructorCapturingOuter.' type=kotlin.Int origin=null FUNCTION_REFERENCE 'local final fun (p0: kotlin.Int): .Outer.Inner declared in .testInnerClassConstructorCapturingOuter' type=kotlin.Function1.Outer.Inner> origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null - $receiver: GET_VAR 'val tmp_0: .Outer [val] declared in .testInnerClassConstructorCapturingOuter' type=.Outer origin=null + $receiver: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Outer' type=.Outer origin=null diff --git a/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.fir.txt b/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.fir.txt index 330817e791b..857bd8ef946 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.fir.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.fir.txt @@ -108,8 +108,6 @@ FILE fqName: fileName:/suspendConversion.kt BLOCK_BODY CALL 'public final fun useSuspend (fn: kotlin.coroutines.SuspendFunction0): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.coroutines.SuspendFunction0 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.C [val] - CONSTRUCTOR_CALL 'public constructor () [primary] declared in .C' type=.C origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:bar visibility:local modality:FINAL <> ($receiver:.C) returnType:kotlin.Unit [suspend] $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.C BLOCK_BODY diff --git a/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.txt b/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.txt index 0659949b44f..f851b2796da 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/suspendConversion.txt @@ -109,12 +109,10 @@ FILE fqName: fileName:/suspendConversion.kt BLOCK_BODY CALL 'public final fun useSuspend (fn: kotlin.coroutines.SuspendFunction0): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.coroutines.SuspendFunction0 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.C [val] - CONSTRUCTOR_CALL 'public constructor () [primary] declared in .C' type=.C origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:bar visibility:local modality:FINAL <> ($receiver:.C) returnType:kotlin.Unit [suspend] $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.C BLOCK_BODY CALL 'public final fun bar (): kotlin.Unit declared in .C' type=kotlin.Unit origin=null $this: GET_VAR 'receiver: .C declared in .testWithBoundReceiver.bar' type=.C origin=ADAPTED_FUNCTION_REFERENCE FUNCTION_REFERENCE 'local final fun bar (): kotlin.Unit [suspend] declared in .testWithBoundReceiver' type=kotlin.coroutines.SuspendFunction0 origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null - $receiver: GET_VAR 'val tmp_0: .C [val] declared in .testWithBoundReceiver' type=.C origin=null + $receiver: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .C' type=.C origin=null diff --git a/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.fir.txt b/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.fir.txt index 2033b0c24bb..6243cc610d9 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.fir.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.fir.txt @@ -55,8 +55,6 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Host' type=.Host origin=null CALL 'public final fun use (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.Host [val] - GET_VAR 'var h: .Host [var] declared in .Host.testBoundReceiverLocalVar' type=.Host origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:.Host, p0:kotlin.Int) returnType:kotlin.Unit $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.Host VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int @@ -88,8 +86,6 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt BLOCK_BODY CALL 'public final fun use (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:.Host [val] - CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Host' type=.Host origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:.Host, p0:kotlin.Int) returnType:kotlin.Unit $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.Host VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int diff --git a/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.txt b/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.txt index d8737a88c6c..9c7a9388e33 100644 --- a/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.txt +++ b/compiler/testData/ir/irText/expressions/callableReferences/withArgumentAdaptationAndReceiver.txt @@ -58,8 +58,6 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Host' type=.Host origin=null CALL 'public final fun use (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:.Host [val] - GET_VAR 'var h: .Host [var] declared in .Host.testBoundReceiverLocalVar' type=.Host origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:.Host, p0:kotlin.Int) returnType:kotlin.Unit $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.Host VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int @@ -70,7 +68,7 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int GET_VAR 'p0: kotlin.Int declared in .Host.testBoundReceiverLocalVar.withVararg' type=kotlin.Int origin=null FUNCTION_REFERENCE 'local final fun withVararg (p0: kotlin.Int): kotlin.Unit declared in .Host.testBoundReceiverLocalVar' type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null - $receiver: GET_VAR 'val tmp_0: .Host [val] declared in .Host.testBoundReceiverLocalVar' type=.Host origin=null + $receiver: GET_VAR 'var h: .Host [var] declared in .Host.testBoundReceiverLocalVar' type=.Host origin=null FUN name:testBoundReceiverParameter visibility:public modality:FINAL <> ($this:.Host, h:.Host) returnType:kotlin.Unit $this: VALUE_PARAMETER name: type:.Host VALUE_PARAMETER name:h index:0 type:.Host @@ -93,8 +91,6 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt BLOCK_BODY CALL 'public final fun use (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null fn: BLOCK type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE - VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:.Host [val] - CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Host' type=.Host origin=null FUN ADAPTER_FOR_CALLABLE_REFERENCE name:withVararg visibility:local modality:FINAL <> ($receiver:.Host, p0:kotlin.Int) returnType:kotlin.Unit $receiver: VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:receiver type:.Host VALUE_PARAMETER ADAPTER_PARAMETER_FOR_CALLABLE_REFERENCE name:p0 index:0 type:kotlin.Int @@ -105,7 +101,7 @@ FILE fqName: fileName:/withArgumentAdaptationAndReceiver.kt xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int GET_VAR 'p0: kotlin.Int declared in .Host.testBoundReceiverExpression.withVararg' type=kotlin.Int origin=null FUNCTION_REFERENCE 'local final fun withVararg (p0: kotlin.Int): kotlin.Unit declared in .Host.testBoundReceiverExpression' type=kotlin.Function1 origin=ADAPTED_FUNCTION_REFERENCE reflectionTarget=null - $receiver: GET_VAR 'val tmp_1: .Host [val] declared in .Host.testBoundReceiverExpression' type=.Host origin=null + $receiver: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .Host' type=.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