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