Add intrinsic for KCallable.name property Fixes #KT-11531
This commit is contained in:
committed by
Alexander Udalov
parent
b8e2533b58
commit
4a619db721
@@ -38,13 +38,10 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
|||||||
import org.jetbrains.kotlin.codegen.context.*;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||||
import org.jetbrains.kotlin.codegen.inline.*;
|
import org.jetbrains.kotlin.codegen.inline.*;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicCallable;
|
import org.jetbrains.kotlin.codegen.intrinsics.*;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod;
|
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
|
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicPropertyGetter;
|
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
|
||||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||||
|
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
|
||||||
@@ -1983,8 +1980,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
|
VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||||
resolvedCall = call.getVariableCall();
|
resolvedCall = call.getVariableCall();
|
||||||
}
|
}
|
||||||
receiver = StackValue.receiver(resolvedCall, receiver, this, null);
|
|
||||||
descriptor = resolvedCall.getResultingDescriptor();
|
descriptor = resolvedCall.getResultingDescriptor();
|
||||||
|
|
||||||
|
//Check early if KCallableNameProperty is applicable to prevent closure generation
|
||||||
|
StackValue intrinsicResult = applyIntrinsic(descriptor, KCallableNameProperty.class, resolvedCall, receiver);
|
||||||
|
if (intrinsicResult != null) return intrinsicResult;
|
||||||
|
|
||||||
|
receiver = StackValue.receiver(resolvedCall, receiver, this, null);
|
||||||
if (descriptor instanceof FakeCallableDescriptorForObject) {
|
if (descriptor instanceof FakeCallableDescriptorForObject) {
|
||||||
descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor();
|
descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor();
|
||||||
}
|
}
|
||||||
@@ -1997,17 +2000,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
if (isSyntheticField) {
|
if (isSyntheticField) {
|
||||||
descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
|
descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
|
||||||
}
|
}
|
||||||
if (descriptor instanceof CallableMemberDescriptor) {
|
|
||||||
CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
|
|
||||||
|
|
||||||
IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
|
StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver);
|
||||||
if (intrinsic instanceof IntrinsicPropertyGetter) {
|
if (intrinsicResult != null) return intrinsicResult;
|
||||||
//TODO: intrinsic properties (see intermediateValueForProperty)
|
|
||||||
Type returnType = typeMapper.mapType(memberDescriptor);
|
|
||||||
StackValue intrinsicResult = ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
|
|
||||||
if (intrinsicResult != null) return intrinsicResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor instanceof PropertyDescriptor) {
|
if (descriptor instanceof PropertyDescriptor) {
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||||
@@ -2056,6 +2051,25 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
|
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private StackValue applyIntrinsic(
|
||||||
|
DeclarationDescriptor descriptor,
|
||||||
|
Class<? extends IntrinsicPropertyGetter> intrinsicType,
|
||||||
|
ResolvedCall<?> resolvedCall,
|
||||||
|
@NotNull StackValue receiver
|
||||||
|
) {
|
||||||
|
if (descriptor instanceof CallableMemberDescriptor) {
|
||||||
|
CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
|
||||||
|
IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
|
||||||
|
if (intrinsicType.isInstance(intrinsic)) {
|
||||||
|
//TODO: intrinsic properties (see intermediateValueForProperty)
|
||||||
|
Type returnType = typeMapper.mapType(memberDescriptor);
|
||||||
|
return ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
|
private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
|
||||||
KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
|
KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public class IntrinsicMethods {
|
|||||||
public IntrinsicMethods() {
|
public IntrinsicMethods() {
|
||||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, new JavaClassProperty());
|
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, new JavaClassProperty());
|
||||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
|
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty());
|
||||||
|
intrinsicsMap.registerIntrinsic(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe(), null, "name", -1, new KCallableNameProperty());
|
||||||
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorEnter", 1, MonitorInstruction.MONITOR_ENTER);
|
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorEnter", 1, MonitorInstruction.MONITOR_ENTER);
|
||||||
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
|
intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
|
||||||
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
|
intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf());
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.intrinsics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
class KCallableNameProperty : IntrinsicPropertyGetter() {
|
||||||
|
override fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? {
|
||||||
|
val expressionReceiver = resolvedCall!!.dispatchReceiver as? ExpressionReceiver ?: return null
|
||||||
|
val expression = expressionReceiver.expression as? KtCallableReferenceExpression ?: return null
|
||||||
|
val callableReference = expression.callableReference
|
||||||
|
val descriptor = callableReference.getResolvedCall(codegen.bindingContext)?.resultingDescriptor ?: return null
|
||||||
|
val name = descriptor.name.asString()
|
||||||
|
|
||||||
|
return StackValue.operation(returnType) { iv ->
|
||||||
|
iv.aconst(name)
|
||||||
|
StackValue.coerce(AsmTypes.JAVA_STRING_TYPE, returnType, iv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class A {
|
||||||
|
val a = ""
|
||||||
|
fun b() = ""
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val a = A::a.name
|
||||||
|
val b = A::b.name
|
||||||
|
val c = ::A.name
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public final class A {
|
||||||
|
private final @org.jetbrains.annotations.NotNull field a: java.lang.String
|
||||||
|
public method <init>(): void
|
||||||
|
public final @org.jetbrains.annotations.NotNull method b(): java.lang.String
|
||||||
|
public final @org.jetbrains.annotations.NotNull method getA(): java.lang.String
|
||||||
|
public final method test(): void
|
||||||
|
}
|
||||||
@@ -35,6 +35,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("callableNameIntrinsic.kt")
|
||||||
|
public void testCallableNameIntrinsic() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("defaultImpls.kt")
|
@TestMetadata("defaultImpls.kt")
|
||||||
public void testDefaultImpls() throws Exception {
|
public void testDefaultImpls() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user