Properly process primitive receiver on inlining bound callable references

#KT-18728 Fixed
This commit is contained in:
Mikhael Bogdanov
2017-06-30 13:11:53 +02:00
parent fe17c4416e
commit 49252f6eec
17 changed files with 404 additions and 5 deletions
@@ -20,8 +20,7 @@ import com.intellij.psi.PsiElement
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn
import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm
import org.jetbrains.kotlin.codegen.intrinsics.bytecode
@@ -657,7 +656,8 @@ class PsiInlineCodegen(
val receiver = getBoundCallableReferenceReceiver(argumentExpression)
if (receiver != null) {
putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver))
val receiverValue = codegen.gen(receiver)
putClosureParametersOnStack(lambdaInfo, StackValue.coercion(receiverValue, receiverValue.type.boxReceiverForBoundReference()))
}
}
else {
@@ -105,6 +105,9 @@ class DefaultLambda(
override fun isMyLabel(name: String): Boolean = false
var originalBoundReceiverType: Type? = null
private set
override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) {
val classReader = buildClassReaderByInternalName(sourceCompiler.state, lambdaClassType.internalName)
var isPropertyReference = false
@@ -141,7 +144,8 @@ class DefaultLambda(
capturedVars =
if (isFunctionReference || isPropertyReference)
constructor?.desc?.let { Type.getArgumentTypes(it) }?.singleOrNull()?.let {
listOf(capturedParamDesc(AsmUtil.RECEIVER_NAME, it))
originalBoundReceiverType = it
listOf(capturedParamDesc(AsmUtil.RECEIVER_NAME, it.boxReceiverForBoundReference()))
} ?: emptyList()
else
constructor?.findCapturedFieldAssignmentInstructions()?.map {
@@ -169,6 +173,9 @@ class DefaultLambda(
}
}
fun Type.boxReceiverForBoundReference() = AsmUtil.boxType(this)
class ExpressionLambda(
expression: KtExpression,
private val typeMapper: KotlinTypeMapper,
@@ -237,7 +244,9 @@ class ExpressionLambda(
}
if (closure.captureReceiverType != null) {
val type = typeMapper.mapType(closure.captureReceiverType!!)
val type = typeMapper.mapType(closure.captureReceiverType!!).let {
if (isBoundCallableReference) it.boxReceiverForBoundReference() else it
}
val descriptor = EnclosedValueDescriptor(
AsmUtil.CAPTURED_RECEIVER_FIELD, null,
StackValue.field(type, lambdaClassType, AsmUtil.CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0),
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClosureCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
@@ -347,6 +348,10 @@ class MethodInliner(
val lambda = getLambdaIfExists(index) as DefaultLambda
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach {
(_, captured) ->
val originalBoundReceiverType = lambda.originalBoundReceiverType
if (lambda.isBoundCallableReference && AsmUtil.isPrimitive(originalBoundReceiverType)) {
StackValue.onStack(originalBoundReceiverType!!).put(captured.type, InstructionAdapter(this))
}
super.visitFieldInsn(
Opcodes.PUTSTATIC, captured.containingLambdaName, CAPTURED_FIELD_FOLD_PREFIX + captured.fieldName, captured.type.descriptor
)