Simplify codegen for trait methods with implementations
- use existing framework (FunctionCodegen.generateMethod) which will take care of all subtleties of method generation (bridges, annotations, thrown exceptions, etc) - call to "generateThisOrOuter" was not needed, since when we're generating delegation to TImpl, "this" is always "ALOAD 0"
This commit is contained in:
@@ -2210,6 +2210,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
|
||||
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
|
||||
if (isSingleton) {
|
||||
@@ -2227,8 +2228,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
boolean inStartConstructorContext = cur instanceof ConstructorContext;
|
||||
while (cur != null) {
|
||||
ClassDescriptor thisDescriptor = cur.getThisDescriptor();
|
||||
if (!isSuper && thisDescriptor.equals(calleeContainingClass)
|
||||
|| isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
|
||||
|
||||
if (!isSuper && thisDescriptor == calleeContainingClass) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
|
||||
return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
|
||||
endVisit(mv, null, origin);
|
||||
|
||||
generateBridgeIfNeeded(owner, state, v, functionDescriptor);
|
||||
generateBridgeIfNeeded(functionDescriptor);
|
||||
|
||||
methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
|
||||
}
|
||||
@@ -404,12 +404,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
static void generateBridgeIfNeeded(
|
||||
CodegenContext owner,
|
||||
GenerationState state,
|
||||
ClassBuilder v,
|
||||
FunctionDescriptor functionDescriptor
|
||||
) {
|
||||
private void generateBridgeIfNeeded(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
|
||||
return;
|
||||
}
|
||||
@@ -775,6 +770,6 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
|
||||
endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
|
||||
descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
|
||||
|
||||
generateBridgeIfNeeded(owner, state, v, functionDescriptor);
|
||||
generateBridgeIfNeeded(functionDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -64,7 +63,6 @@ import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.jet.codegen.CodegenUtil.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||
import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
|
||||
@@ -1464,21 +1462,28 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
private void generateTraitMethods() {
|
||||
if (JetPsiUtil.isTrait(myClass)) {
|
||||
return;
|
||||
}
|
||||
if (JetPsiUtil.isTrait(myClass)) return;
|
||||
|
||||
for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) {
|
||||
if (needDelegates.second instanceof SimpleFunctionDescriptor) {
|
||||
generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first);
|
||||
for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> pair : getTraitImplementations(descriptor)) {
|
||||
CallableMemberDescriptor inheritedMember = pair.first;
|
||||
CallableMemberDescriptor traitMember = pair.second;
|
||||
|
||||
assert traitMember.getModality() != Modality.ABSTRACT : "Cannot delegate to abstract trait method: " + pair;
|
||||
|
||||
// inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
|
||||
// with traitMember's modality
|
||||
CallableMemberDescriptor copy =
|
||||
inheritedMember.copy(inheritedMember.getContainingDeclaration(), traitMember.getModality(), Visibilities.PUBLIC,
|
||||
CallableMemberDescriptor.Kind.DECLARATION, true);
|
||||
|
||||
if (traitMember instanceof SimpleFunctionDescriptor) {
|
||||
generateDelegationToTraitImpl((FunctionDescriptor) traitMember, (FunctionDescriptor) copy);
|
||||
}
|
||||
else if (needDelegates.second instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor property = (PropertyDescriptor) needDelegates.second;
|
||||
List<PropertyAccessorDescriptor> inheritedAccessors = ((PropertyDescriptor) needDelegates.first).getAccessors();
|
||||
for (PropertyAccessorDescriptor accessor : property.getAccessors()) {
|
||||
for (PropertyAccessorDescriptor inheritedAccessor : inheritedAccessors) {
|
||||
if (inheritedAccessor.getClass() == accessor.getClass()) { // same accessor kind
|
||||
generateDelegationToTraitImpl(accessor, inheritedAccessor);
|
||||
else if (traitMember instanceof PropertyDescriptor) {
|
||||
for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) {
|
||||
for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) {
|
||||
if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind
|
||||
generateDelegationToTraitImpl(traitAccessor, inheritedAccessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1486,58 +1491,42 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDelegationToTraitImpl(@NotNull final FunctionDescriptor traitFun, @NotNull FunctionDescriptor inheritedFun) {
|
||||
functionCodegen.generateMethod(
|
||||
descriptorToDeclaration(bindingContext, traitFun),
|
||||
typeMapper.mapSignature(inheritedFun),
|
||||
inheritedFun,
|
||||
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, inheritedFun) {
|
||||
@Override
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
DeclarationDescriptor containingDeclaration = traitFun.getContainingDeclaration();
|
||||
if (!(containingDeclaration instanceof ClassDescriptor)) return;
|
||||
ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration;
|
||||
if (containingTrait.getKind() != ClassKind.TRAIT) return;
|
||||
|
||||
private void generateDelegationToTraitImpl(@NotNull FunctionDescriptor fun, @NotNull FunctionDescriptor inheritedFun) {
|
||||
DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
|
||||
if (!(containingDeclaration instanceof ClassDescriptor)) {
|
||||
return;
|
||||
}
|
||||
Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal()).getAsmMethod();
|
||||
|
||||
ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
|
||||
if (containingClass.getKind() != ClassKind.TRAIT) {
|
||||
return;
|
||||
}
|
||||
Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
|
||||
Type[] originalArgTypes = traitMethod.getArgumentTypes();
|
||||
|
||||
int flags = ACC_PUBLIC; // TODO.
|
||||
InstructionAdapter iv = codegen.v;
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
reg += argTypes[i].getSize();
|
||||
}
|
||||
|
||||
Method methodToGenerate = typeMapper.mapSignature(fun).getAsmMethod();
|
||||
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
|
||||
Type type = getTraitImplThisParameterType(containingTrait, typeMapper);
|
||||
String desc = traitMethod.getDescriptor().replace("(", "(" + type.getDescriptor());
|
||||
|
||||
PsiElement origin = descriptorToDeclaration(bindingContext, fun);
|
||||
MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null,
|
||||
CodegenUtil.getExceptions(fun, typeMapper));
|
||||
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
|
||||
iv.invokestatic(typeMapper.mapTraitImpl(containingTrait).getInternalName(), traitMethod.getName(), desc);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
Type returnType = methodToGenerate.getReturnType();
|
||||
|
||||
mv.visitCode();
|
||||
FrameMap frameMap = context.prepareFrame(typeMapper);
|
||||
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state, this);
|
||||
codegen.generateThisOrOuter(descriptor, false); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
|
||||
|
||||
Type[] argTypes = methodToGenerate.getArgumentTypes();
|
||||
Type[] originalArgTypes = methodInTrait.getArgumentTypes();
|
||||
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
iv.load(0, OBJECT_TYPE);
|
||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
|
||||
//noinspection AssignmentToForLoopParameter
|
||||
reg += argTypes[i].getSize();
|
||||
Type returnType = signature.getReturnType();
|
||||
StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv);
|
||||
iv.areturn(returnType);
|
||||
}
|
||||
|
||||
Type type = getTraitImplThisParameterType(containingClass, typeMapper);
|
||||
String functionDescriptor = methodInTrait.getDescriptor().replace("(", "(" + type.getDescriptor());
|
||||
|
||||
iv.invokestatic(typeMapper.mapTraitImpl(containingClass).getInternalName(), methodToGenerate.getName(), functionDescriptor);
|
||||
StackValue.onStack(methodInTrait.getReturnType()).put(returnType, iv);
|
||||
iv.areturn(returnType);
|
||||
|
||||
FunctionCodegen.endVisit(iv, "trait method", callableDescriptorToDeclaration(bindingContext, fun));
|
||||
}
|
||||
|
||||
FunctionCodegen.generateBridgeIfNeeded(context, state, v, fun);
|
||||
});
|
||||
}
|
||||
|
||||
private void generateDelegatorToConstructorCall(
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -32,10 +31,7 @@ import org.jetbrains.jet.lang.psi.JetTypeReference;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
|
||||
import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
|
||||
@@ -162,11 +158,11 @@ public final class DelegationResolver<T extends CallableMemberDescriptor> {
|
||||
@NotNull
|
||||
private Collection<T> generateDelegationCandidates(@NotNull JetType delegatedTraitType) {
|
||||
Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType);
|
||||
Collection<T> result = Lists.newArrayList();
|
||||
Collection<T> result = new ArrayList<T>(descriptorsToDelegate.size());
|
||||
for (T memberDescriptor : descriptorsToDelegate) {
|
||||
Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
|
||||
Modality newModality = memberDescriptor.getModality() == Modality.ABSTRACT ? Modality.OPEN : memberDescriptor.getModality();
|
||||
@SuppressWarnings("unchecked")
|
||||
T copy = (T) memberDescriptor.copy(ownerDescriptor, modality, memberDescriptor.getVisibility(),
|
||||
T copy = (T) memberDescriptor.copy(ownerDescriptor, newModality, memberDescriptor.getVisibility(),
|
||||
CallableMemberDescriptor.Kind.DELEGATION, false);
|
||||
result.add(copy);
|
||||
}
|
||||
|
||||
+6
-6
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorFactory;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
|
||||
@@ -243,16 +242,17 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
|
||||
substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType);
|
||||
|
||||
PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl(
|
||||
substitutedDescriptor, getter.getAnnotations(),
|
||||
DescriptorUtils.convertModality(getter.getModality(), false), convertVisibility(getter.getVisibility(), newVisibility),
|
||||
getter.hasBody(), getter.isDefault(), kind, getter.getOriginal());
|
||||
substitutedDescriptor, getter.getAnnotations(), newModality, convertVisibility(getter.getVisibility(), newVisibility),
|
||||
getter.hasBody(), getter.isDefault(), kind, getter.getOriginal()
|
||||
);
|
||||
if (newGetter != null) {
|
||||
JetType returnType = getter.getReturnType();
|
||||
newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null);
|
||||
}
|
||||
PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl(
|
||||
substitutedDescriptor, setter.getAnnotations(), DescriptorUtils.convertModality(setter.getModality(), false),
|
||||
convertVisibility(setter.getVisibility(), newVisibility), setter.hasBody(), setter.isDefault(), kind, setter.getOriginal());
|
||||
substitutedDescriptor, setter.getAnnotations(), newModality, convertVisibility(setter.getVisibility(), newVisibility),
|
||||
setter.hasBody(), setter.isDefault(), kind, setter.getOriginal()
|
||||
);
|
||||
if (newSetter != null) {
|
||||
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor);
|
||||
if (substitutedValueParameters == null) {
|
||||
|
||||
@@ -57,12 +57,6 @@ public class DescriptorUtils {
|
||||
return substitutedFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Modality convertModality(@NotNull Modality modality, boolean makeNonAbstract) {
|
||||
if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
|
||||
return modality;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
|
||||
if (containingDeclaration instanceof ClassDescriptor) {
|
||||
|
||||
Reference in New Issue
Block a user