Fix exception on inlining callable reference with implicit this in LHS
Use ResolvedCall to determine the receiver type in the JVM codegen, instead of manually inspecting the PSI #KT-20821 Fixed
This commit is contained in:
@@ -2839,14 +2839,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@Nullable
|
||||
public StackValue generateCallableReferenceReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
if (descriptor.getExtensionReceiverParameter() == null && descriptor.getDispatchReceiverParameter() == null) return null;
|
||||
|
||||
ReceiverValue dispatchReceiver = resolvedCall.getDispatchReceiver();
|
||||
ReceiverValue extensionReceiver = resolvedCall.getExtensionReceiver();
|
||||
assert dispatchReceiver == null || extensionReceiver == null : "Cannot generate reference with both receivers: " + descriptor;
|
||||
ReceiverValue receiver = dispatchReceiver != null ? dispatchReceiver : extensionReceiver;
|
||||
if (receiver == null || receiver instanceof TransientReceiver) return null;
|
||||
ReceiverValue receiver = getBoundCallableReferenceReceiver(resolvedCall);
|
||||
if (receiver == null) return null;
|
||||
|
||||
return StackValue.coercion(generateReceiverValue(receiver, false), asmType(receiver.getType()));
|
||||
}
|
||||
|
||||
@@ -41,8 +41,10 @@ import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -313,4 +315,19 @@ public class JvmCodegenUtil {
|
||||
public static boolean isDelegatedLocalVariable(@NotNull DeclarationDescriptor descriptor) {
|
||||
return descriptor instanceof LocalVariableDescriptor && ((LocalVariableDescriptor) descriptor).isDelegated();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ReceiverValue getBoundCallableReferenceReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
if (descriptor.getExtensionReceiverParameter() == null && descriptor.getDispatchReceiverParameter() == null) return null;
|
||||
|
||||
ReceiverValue dispatchReceiver = resolvedCall.getDispatchReceiver();
|
||||
ReceiverValue extensionReceiver = resolvedCall.getExtensionReceiver();
|
||||
assert dispatchReceiver == null || extensionReceiver == null : "Cannot generate reference with both receivers: " + descriptor;
|
||||
ReceiverValue receiver = dispatchReceiver != null ? dispatchReceiver : extensionReceiver;
|
||||
|
||||
if (receiver instanceof TransientReceiver) return null;
|
||||
|
||||
return receiver;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,10 @@ import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
|
||||
@@ -48,8 +48,8 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral
|
||||
import org.jetbrains.kotlin.types.expressions.LabelResolver
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -704,19 +704,10 @@ class PsiInlineCodegen(
|
||||
activeLambda = null
|
||||
}
|
||||
|
||||
|
||||
private fun getBoundCallableReferenceReceiver(
|
||||
argumentExpression: KtExpression
|
||||
): KtExpression? {
|
||||
val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression)
|
||||
if (deparenthesized is KtCallableReferenceExpression) {
|
||||
val receiverExpression = deparenthesized.receiverExpression
|
||||
if (receiverExpression != null) {
|
||||
val lhs = state.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression)
|
||||
if (lhs is DoubleColonLHS.Expression) return receiverExpression
|
||||
}
|
||||
}
|
||||
return null
|
||||
private fun getBoundCallableReferenceReceiver(argumentExpression: KtExpression): ReceiverValue? {
|
||||
val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) as? KtCallableReferenceExpression ?: return null
|
||||
val resolvedCall = deparenthesized.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
return JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)
|
||||
}
|
||||
|
||||
/*lambda or callable reference*/
|
||||
@@ -736,10 +727,10 @@ class PsiInlineCodegen(
|
||||
if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
|
||||
val lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor)
|
||||
|
||||
val receiver = getBoundCallableReferenceReceiver(argumentExpression)
|
||||
if (receiver != null) {
|
||||
val receiverValue = codegen.gen(receiver)
|
||||
putClosureParametersOnStack(lambdaInfo, StackValue.coercion(receiverValue, receiverValue.type.boxReceiverForBoundReference()))
|
||||
val receiverValue = getBoundCallableReferenceReceiver(argumentExpression)
|
||||
if (receiverValue != null) {
|
||||
val receiver = codegen.generateReceiverValue(receiverValue, false)
|
||||
putClosureParametersOnStack(lambdaInfo, StackValue.coercion(receiver, receiver.type.boxReceiverForBoundReference()))
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
+6
-15
@@ -38,7 +38,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import java.util.HashMap
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
interface SourceCompilerForInline {
|
||||
@@ -174,28 +174,19 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
|
||||
|
||||
val strategy = when (expression) {
|
||||
is KtCallableReferenceExpression -> {
|
||||
val receiverExpression = expression.receiverExpression
|
||||
val receiverType = if (receiverExpression != null && state.bindingContext.getType(receiverExpression) != null)
|
||||
state.typeMapper.mapType(state.bindingContext.getType(receiverExpression)!!)
|
||||
else
|
||||
null
|
||||
val resolvedCall = expression.callableReference.getResolvedCallWithAssert(state.bindingContext)
|
||||
val receiverType = JvmCodegenUtil.getBoundCallableReferenceReceiver(resolvedCall)?.type?.let(state.typeMapper::mapType)
|
||||
|
||||
if (isLambda && lambdaInfo!!.isPropertyReference) {
|
||||
val asmType = state.typeMapper.mapClass(lambdaInfo.classDescriptor)
|
||||
val info = lambdaInfo.propertyReferenceInfo
|
||||
PropertyReferenceCodegen.PropertyReferenceGenerationStrategy(
|
||||
true, info!!.getFunction, info.target, asmType, receiverType,
|
||||
lambdaInfo.functionWithBodyOrCallableReference, state, true)
|
||||
lambdaInfo.functionWithBodyOrCallableReference, state, true
|
||||
)
|
||||
}
|
||||
else {
|
||||
FunctionReferenceGenerationStrategy(
|
||||
state,
|
||||
descriptor,
|
||||
expression.callableReference
|
||||
.getResolvedCallWithAssert(state.bindingContext),
|
||||
receiverType, null,
|
||||
true
|
||||
)
|
||||
FunctionReferenceGenerationStrategy(state, descriptor, resolvedCall, receiverType, null, true)
|
||||
}
|
||||
}
|
||||
is KtFunctionLiteral -> ClosureGenerationStrategy(state, expression as KtDeclarationWithBody)
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
class X {
|
||||
fun x(): String {
|
||||
return foo("O", "K", ::y)
|
||||
}
|
||||
|
||||
fun y(a: String, b: String): String = a + b
|
||||
}
|
||||
|
||||
inline fun foo(a: String, b: String, f: (String, String) -> String): String {
|
||||
return f(a, b)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return X().x()
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
class X {
|
||||
val result: String
|
||||
inline get() = "OK"
|
||||
|
||||
fun x(): String {
|
||||
return go(::result)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun go(f: () -> String): String = f()
|
||||
|
||||
fun box(): String {
|
||||
return X().x()
|
||||
}
|
||||
+12
@@ -745,6 +745,18 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsFunction.kt")
|
||||
public void testEmptyLhsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsProperty.kt")
|
||||
public void testEmptyLhsProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
|
||||
+12
@@ -745,6 +745,18 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsFunction.kt")
|
||||
public void testEmptyLhsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsProperty.kt")
|
||||
public void testEmptyLhsProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
|
||||
@@ -745,6 +745,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsFunction.kt")
|
||||
public void testEmptyLhsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsProperty.kt")
|
||||
public void testEmptyLhsProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
|
||||
+12
@@ -745,6 +745,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsFunction.kt")
|
||||
public void testEmptyLhsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsProperty.kt")
|
||||
public void testEmptyLhsProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
|
||||
+12
@@ -116,6 +116,18 @@ public class CallableReferenceInlineTestsGenerated extends AbstractCallableRefer
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsFunction.kt")
|
||||
public void testEmptyLhsFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyLhsProperty.kt")
|
||||
public void testEmptyLhsProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/emptyLhsProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("expression.kt")
|
||||
public void testExpression() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/expression.kt");
|
||||
|
||||
Reference in New Issue
Block a user