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:
pyos
2020-10-06 16:14:13 +02:00
committed by max-kammerer
parent 369056ca5d
commit ccf921510d
8 changed files with 16 additions and 52 deletions
@@ -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)
}
}
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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