Generate proper generic signature for closure classes

This commit is contained in:
Alexander Udalov
2013-04-22 15:51:15 +04:00
parent ace7bd9bc8
commit 56f8f021f9
7 changed files with 120 additions and 58 deletions
@@ -25,10 +25,10 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.asm4.signature.SignatureWriter;
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.LocalLookup;
import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
@@ -43,12 +43,13 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
import static org.jetbrains.jet.codegen.FunctionTypesUtil.getFunctionImplClassName;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
public class ClosureCodegen extends GenerationStateAware {
@@ -290,40 +291,22 @@ public class ClosureCodegen extends GenerationStateAware {
@NotNull
private String getGenericSignature() {
SignatureWriter signatureWriter = new SignatureWriter();
JvmClassName funClass = getFunctionImplClassName(funDescriptor);
signatureWriter.visitClassType(funClass.getInternalName());
ReceiverParameterDescriptor receiverParameter = funDescriptor.getReceiverParameter();
if (receiverParameter != null) {
appendType(signatureWriter, receiverParameter.getType(), '=');
}
for (ValueParameterDescriptor parameter : funDescriptor.getValueParameters()) {
appendType(signatureWriter, parameter.getType(), '=');
}
ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor);
Collection<JetType> supertypes = classDescriptor.getTypeConstructor().getSupertypes();
assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor;
JetType supertype = supertypes.iterator().next();
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
signatureWriter.visitEnd();
BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true);
typeMapper.writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), sw);
sw.writeSupersStart();
sw.writeSuperclass();
typeMapper.mapType(supertype, sw, JetTypeMapperMode.TYPE_PARAMETER);
sw.writeSuperclassEnd();
sw.writeSupersEnd();
return signatureWriter.toString();
}
private void appendType(SignatureWriter signatureWriter, JetType type, char variance) {
signatureWriter.visitTypeArgument(variance);
Type rawRetType = typeMapper.mapType(type, JetTypeMapperMode.TYPE_PARAMETER);
while (rawRetType.getSort() == Type.ARRAY) {
signatureWriter.visitArrayType();
rawRetType = rawRetType.getElementType();
}
if (rawRetType.getSort() == Type.OBJECT) {
signatureWriter.visitClassType(rawRetType.getInternalName());
signatureWriter.visitEnd();
}
else {
assert isPrimitive(rawRetType);
signatureWriter.visitBaseType(rawRetType.getDescriptor().charAt(0));
}
String signature = sw.makeJavaGenericSignature();
assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor;
return signature;
}
private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) {
@@ -25,6 +25,8 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeImpl;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.ArrayList;
@@ -85,13 +87,54 @@ public class FunctionTypesUtil {
}
@NotNull
public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor funDescriptor, int arity) {
if (funDescriptor.getReceiverParameter() != null) {
return EXTENSION_FUNCTIONS.get(arity).getDefaultType();
public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor descriptor, boolean kFunction) {
int arity = descriptor.getValueParameters().size();
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
List<TypeProjection> typeArguments = new ArrayList<TypeProjection>(arity + 2);
if (receiverParameter != null) {
typeArguments.add(new TypeProjection(receiverParameter.getType()));
}
else if (kFunction && expectedThisObject != null) {
typeArguments.add(new TypeProjection(expectedThisObject.getType()));
}
for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
typeArguments.add(new TypeProjection(parameter.getType()));
}
typeArguments.add(new TypeProjection(descriptor.getReturnType()));
ClassDescriptor classDescriptor;
if (kFunction) {
if (expectedThisObject != null) {
classDescriptor = K_MEMBER_FUNCTIONS.get(arity);
}
else if (receiverParameter != null) {
classDescriptor = K_EXTENSION_FUNCTIONS.get(arity);
}
else {
classDescriptor = K_FUNCTIONS.get(arity);
}
}
else {
return FUNCTIONS.get(arity).getDefaultType();
if (receiverParameter != null) {
classDescriptor = EXTENSION_FUNCTIONS.get(arity);
}
else {
classDescriptor = FUNCTIONS.get(arity);
}
}
return new JetTypeImpl(
classDescriptor.getDefaultType().getAnnotations(),
classDescriptor.getTypeConstructor(),
false,
typeArguments,
classDescriptor.getMemberScope(typeArguments)
);
}
@NotNull
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.HashMap;
@@ -80,9 +81,9 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
}
}
private ClassDescriptor recordClassForFunction(FunctionDescriptor funDescriptor) {
@NotNull
private ClassDescriptor recordClassForFunction(@NotNull FunctionDescriptor funDescriptor, @NotNull JetType superType) {
ClassDescriptor classDescriptor;
int arity = funDescriptor.getValueParameters().size();
classDescriptor = new ClassDescriptorImpl(
funDescriptor.getContainingDeclaration(),
@@ -92,7 +93,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
((ClassDescriptorImpl)classDescriptor).initialize(
false,
Collections.<TypeParameterDescriptor>emptyList(),
Collections.singleton(getSuperTypeForClosure(funDescriptor, arity)),
Collections.singleton(superType),
JetScope.EMPTY,
Collections.<ConstructorDescriptor>emptySet(),
null,
@@ -258,7 +259,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
if (functionDescriptor == null) return;
String name = inventAnonymousClassName(expression);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
JetType superType = getSuperTypeForClosure(functionDescriptor, false);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(functionLiteral, classDescriptor, name, true);
classStack.push(classDescriptor);
@@ -274,8 +276,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
// working around a problem with shallow analysis
if (functionDescriptor == null) return;
ResolvedCall<? extends CallableDescriptor> referencedFunction =
bindingContext.get(RESOLVED_CALL, expression.getCallableReference());
if (referencedFunction == null) return;
JetType superType = getSuperTypeForClosure((FunctionDescriptor) referencedFunction.getResultingDescriptor(), true);
String name = inventAnonymousClassName(expression);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(expression, classDescriptor, name, true);
classStack.push(classDescriptor);
@@ -326,7 +333,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
}
else {
String name = inventAnonymousClassName(function);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
JetType superType = getSuperTypeForClosure(functionDescriptor, false);
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
recordClosure(function, classDescriptor, name, true);
classStack.push(classDescriptor);