Add intrinsic for KCallable.name property Fixes #KT-11531

This commit is contained in:
Kirill Rakhman
2016-04-22 20:54:49 +02:00
committed by Alexander Udalov
parent b8e2533b58
commit 4a619db721
6 changed files with 96 additions and 16 deletions
@@ -38,13 +38,10 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicCallable;
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.intrinsics.*;
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.JvmSignatureWriter;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
@@ -1983,8 +1980,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
resolvedCall = call.getVariableCall();
}
receiver = StackValue.receiver(resolvedCall, receiver, this, null);
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) {
descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor();
}
@@ -1997,17 +2000,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (isSyntheticField) {
descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
}
if (descriptor instanceof CallableMemberDescriptor) {
CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
if (intrinsic instanceof IntrinsicPropertyGetter) {
//TODO: intrinsic properties (see intermediateValueForProperty)
Type returnType = typeMapper.mapType(memberDescriptor);
StackValue intrinsicResult = ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
if (intrinsicResult != null) return intrinsicResult;
}
}
StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver);
if (intrinsicResult != null) return intrinsicResult;
if (descriptor instanceof PropertyDescriptor) {
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);
}
@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
private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
@@ -62,6 +62,7 @@ public class IntrinsicMethods {
public IntrinsicMethods() {
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(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, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT);
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);
}
@TestMetadata("callableNameIntrinsic.kt")
public void testCallableNameIntrinsic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt");
doTest(fileName);
}
@TestMetadata("defaultImpls.kt")
public void testDefaultImpls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");