Convert TraitImplBodyCodegen to Kotlin
This commit is contained in:
@@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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;
|
|
||||||
|
|
||||||
import com.intellij.util.ArrayUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.ClassContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
|
|
||||||
import org.jetbrains.kotlin.psi.JetClassOrObject;
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.backend.common.bridges.BridgesPackage.findImplementationFromInterface;
|
|
||||||
import static org.jetbrains.kotlin.backend.common.bridges.BridgesPackage.firstSuperMethodFromKotlin;
|
|
||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation;
|
|
||||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
|
||||||
|
|
||||||
public class TraitImplBodyCodegen extends ClassBodyCodegen {
|
|
||||||
public TraitImplBodyCodegen(
|
|
||||||
@NotNull JetClassOrObject aClass,
|
|
||||||
@NotNull ClassContext context,
|
|
||||||
@NotNull ClassBuilder v,
|
|
||||||
@NotNull GenerationState state,
|
|
||||||
@Nullable MemberCodegen<?> parentCodegen
|
|
||||||
) {
|
|
||||||
super(aClass, context, v, state, parentCodegen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateDeclaration() {
|
|
||||||
v.defineClass(myClass, V1_6,
|
|
||||||
ACC_PUBLIC | ACC_FINAL,
|
|
||||||
typeMapper.mapTraitImpl(descriptor).getInternalName(),
|
|
||||||
null,
|
|
||||||
"java/lang/Object",
|
|
||||||
ArrayUtil.EMPTY_STRING_ARRAY
|
|
||||||
);
|
|
||||||
v.visitSource(myClass.getContainingFile().getName(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateSyntheticParts() {
|
|
||||||
for (DeclarationDescriptor memberDescriptor : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
|
|
||||||
if (!(memberDescriptor instanceof CallableMemberDescriptor)) continue;
|
|
||||||
|
|
||||||
CallableMemberDescriptor fakeOverride = (CallableMemberDescriptor) memberDescriptor;
|
|
||||||
if (fakeOverride.getKind().isReal()) continue;
|
|
||||||
if (fakeOverride.getVisibility() == Visibilities.INVISIBLE_FAKE) continue;
|
|
||||||
if (fakeOverride.getModality() == Modality.ABSTRACT) continue;
|
|
||||||
|
|
||||||
CallableMemberDescriptor implementation = findImplementationFromInterface(fakeOverride);
|
|
||||||
if (implementation == null) continue;
|
|
||||||
|
|
||||||
// If implementation is located in a Java interface, it will be inherited via normal Java rules
|
|
||||||
if (implementation instanceof JavaMethodDescriptor) continue;
|
|
||||||
|
|
||||||
// We create a copy of the function with kind = DECLARATION so that FunctionCodegen will generate its body
|
|
||||||
CallableMemberDescriptor copy = fakeOverride.copy(
|
|
||||||
fakeOverride.getContainingDeclaration(), Modality.OPEN, fakeOverride.getVisibility(),
|
|
||||||
CallableMemberDescriptor.Kind.DECLARATION, true
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fakeOverride instanceof FunctionDescriptor) {
|
|
||||||
generateDelegationToSuperTraitImpl((FunctionDescriptor) copy, (FunctionDescriptor) implementation);
|
|
||||||
}
|
|
||||||
else if (fakeOverride instanceof PropertyDescriptor) {
|
|
||||||
PropertyGetterDescriptor getter = ((PropertyDescriptor) copy).getGetter();
|
|
||||||
PropertyGetterDescriptor implGetter = ((PropertyDescriptor) implementation).getGetter();
|
|
||||||
if (getter != null && implGetter != null) {
|
|
||||||
generateDelegationToSuperTraitImpl(getter, implGetter);
|
|
||||||
}
|
|
||||||
PropertySetterDescriptor setter = ((PropertyDescriptor) copy).getSetter();
|
|
||||||
PropertySetterDescriptor implSetter = ((PropertyDescriptor) implementation).getSetter();
|
|
||||||
if (setter != null && implSetter != null) {
|
|
||||||
generateDelegationToSuperTraitImpl(setter, implSetter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateDelegationToSuperTraitImpl(@NotNull FunctionDescriptor descriptor, @NotNull FunctionDescriptor implementation) {
|
|
||||||
final FunctionDescriptor delegateTo = (FunctionDescriptor) firstSuperMethodFromKotlin(descriptor, implementation);
|
|
||||||
if (delegateTo == null) return;
|
|
||||||
|
|
||||||
// We can't call super methods from Java 1.8 interfaces because that requires INVOKESPECIAL which is forbidden from TImpl class
|
|
||||||
if (delegateTo instanceof JavaMethodDescriptor) return;
|
|
||||||
|
|
||||||
functionCodegen.generateMethod(
|
|
||||||
DiagnosticsPackage.DelegationToTraitImpl(descriptorToDeclaration(descriptor), descriptor),
|
|
||||||
descriptor,
|
|
||||||
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, descriptor) {
|
|
||||||
@Override
|
|
||||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
|
||||||
InstructionAdapter iv = codegen.v;
|
|
||||||
|
|
||||||
CallableMethod method = typeMapper.mapToCallableMethod(delegateTo, true, context);
|
|
||||||
List<JvmMethodParameterSignature> myParameters = signature.getValueParameters();
|
|
||||||
List<JvmMethodParameterSignature> calleeParameters = method.getValueParameters();
|
|
||||||
|
|
||||||
if (myParameters.size() != calleeParameters.size()) {
|
|
||||||
throw new AssertionError(
|
|
||||||
String.format(
|
|
||||||
"Method from super interface has a different signature.\n" +
|
|
||||||
"This method:\n%s\n%s\n%s\nSuper method:\n%s\n%s\n%s",
|
|
||||||
callableDescriptor, signature, myParameters, delegateTo, method, calleeParameters
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
int k = 0;
|
|
||||||
Iterator<JvmMethodParameterSignature> it = calleeParameters.iterator();
|
|
||||||
for (JvmMethodParameterSignature parameter : myParameters) {
|
|
||||||
Type type = parameter.getAsmType();
|
|
||||||
StackValue.local(k, type).put(it.next().getAsmType(), iv);
|
|
||||||
k += type.getSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
method.genInvokeInstruction(iv);
|
|
||||||
StackValue.coerce(method.getReturnType(), signature.getReturnType(), iv);
|
|
||||||
iv.areturn(signature.getReturnType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void generateKotlinAnnotation() {
|
|
||||||
writeKotlinSyntheticClassAnnotation(v, DescriptorUtils.isTopLevelOrInnerClass(descriptor)
|
|
||||||
? KotlinSyntheticClass.Kind.TRAIT_IMPL
|
|
||||||
: KotlinSyntheticClass.Kind.LOCAL_TRAIT_IMPL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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
|
||||||
|
|
||||||
|
import com.intellij.util.ArrayUtil
|
||||||
|
import org.jetbrains.kotlin.backend.common.bridges.findImplementationFromInterface
|
||||||
|
import org.jetbrains.kotlin.backend.common.bridges.firstSuperMethodFromKotlin
|
||||||
|
import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation
|
||||||
|
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.LOCAL_TRAIT_IMPL
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.TRAIT_IMPL
|
||||||
|
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||||
|
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.DelegationToTraitImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes.V1_6
|
||||||
|
|
||||||
|
public class TraitImplBodyCodegen(
|
||||||
|
aClass: JetClassOrObject,
|
||||||
|
context: ClassContext,
|
||||||
|
v: ClassBuilder,
|
||||||
|
state: GenerationState,
|
||||||
|
parentCodegen: MemberCodegen<*>?
|
||||||
|
) : ClassBodyCodegen(aClass, context, v, state, parentCodegen) {
|
||||||
|
|
||||||
|
override fun generateDeclaration() {
|
||||||
|
v.defineClass(
|
||||||
|
myClass, V1_6, ACC_PUBLIC or ACC_FINAL,
|
||||||
|
typeMapper.mapTraitImpl(descriptor).getInternalName(),
|
||||||
|
null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY
|
||||||
|
)
|
||||||
|
v.visitSource(myClass.getContainingFile().getName(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateSyntheticParts() {
|
||||||
|
for (memberDescriptor in descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
|
||||||
|
if (memberDescriptor !is CallableMemberDescriptor) continue
|
||||||
|
|
||||||
|
if (memberDescriptor.getKind().isReal()) continue
|
||||||
|
if (memberDescriptor.getVisibility() == Visibilities.INVISIBLE_FAKE) continue
|
||||||
|
if (memberDescriptor.getModality() == Modality.ABSTRACT) continue
|
||||||
|
|
||||||
|
val implementation = findImplementationFromInterface(memberDescriptor) ?: continue
|
||||||
|
|
||||||
|
// If implementation is located in a Java interface, it will be inherited via normal Java rules
|
||||||
|
if (implementation is JavaMethodDescriptor) continue
|
||||||
|
|
||||||
|
// We create a copy of the function with kind = DECLARATION so that FunctionCodegen will generate its body
|
||||||
|
val copy = memberDescriptor.copy(memberDescriptor.getContainingDeclaration(), Modality.OPEN, memberDescriptor.getVisibility(),
|
||||||
|
CallableMemberDescriptor.Kind.DECLARATION, true)
|
||||||
|
|
||||||
|
if (memberDescriptor is FunctionDescriptor) {
|
||||||
|
generateDelegationToSuperTraitImpl(copy as FunctionDescriptor, implementation as FunctionDescriptor)
|
||||||
|
}
|
||||||
|
else if (memberDescriptor is PropertyDescriptor) {
|
||||||
|
implementation as PropertyDescriptor
|
||||||
|
val getter = (copy as PropertyDescriptor).getGetter()
|
||||||
|
val implGetter = implementation.getGetter()
|
||||||
|
if (getter != null && implGetter != null) {
|
||||||
|
generateDelegationToSuperTraitImpl(getter, implGetter)
|
||||||
|
}
|
||||||
|
val setter = copy.getSetter()
|
||||||
|
val implSetter = implementation.getSetter()
|
||||||
|
if (setter != null && implSetter != null) {
|
||||||
|
generateDelegationToSuperTraitImpl(setter, implSetter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateDelegationToSuperTraitImpl(descriptor: FunctionDescriptor, implementation: FunctionDescriptor) {
|
||||||
|
val delegateTo = firstSuperMethodFromKotlin(descriptor, implementation) as FunctionDescriptor? ?: return
|
||||||
|
|
||||||
|
// We can't call super methods from Java 1.8 interfaces because that requires INVOKESPECIAL which is forbidden from TImpl class
|
||||||
|
if (delegateTo is JavaMethodDescriptor) return
|
||||||
|
|
||||||
|
functionCodegen.generateMethod(
|
||||||
|
DelegationToTraitImpl(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor),
|
||||||
|
descriptor,
|
||||||
|
object : FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, descriptor) {
|
||||||
|
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
|
||||||
|
val iv = codegen.v
|
||||||
|
|
||||||
|
val method = typeMapper.mapToCallableMethod(delegateTo, true, context)
|
||||||
|
val myParameters = signature.getValueParameters()
|
||||||
|
val calleeParameters = method.getValueParameters()
|
||||||
|
|
||||||
|
if (myParameters.size() != calleeParameters.size()) {
|
||||||
|
throw AssertionError(
|
||||||
|
"Method from super interface has a different signature.\n" +
|
||||||
|
"This method:\n%s\n%s\n%s\nSuper method:\n%s\n%s\n%s".format(
|
||||||
|
callableDescriptor, signature, myParameters, delegateTo, method, calleeParameters
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var k = 0
|
||||||
|
val it = calleeParameters.iterator()
|
||||||
|
for (parameter in myParameters) {
|
||||||
|
val type = parameter.getAsmType()
|
||||||
|
StackValue.local(k, type).put(it.next().getAsmType(), iv)
|
||||||
|
k += type.getSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
method.genInvokeInstruction(iv)
|
||||||
|
StackValue.coerce(method.returnType, signature.getReturnType(), iv)
|
||||||
|
iv.areturn(signature.getReturnType())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateKotlinAnnotation() {
|
||||||
|
writeKotlinSyntheticClassAnnotation(
|
||||||
|
v,
|
||||||
|
if (DescriptorUtils.isTopLevelOrInnerClass(descriptor)) TRAIT_IMPL else LOCAL_TRAIT_IMPL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user