Generate proper generic signature for closure classes
This commit is contained in:
@@ -25,10 +25,10 @@ import org.jetbrains.asm4.MethodVisitor;
|
|||||||
import org.jetbrains.asm4.Type;
|
import org.jetbrains.asm4.Type;
|
||||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||||
import org.jetbrains.asm4.commons.Method;
|
import org.jetbrains.asm4.commons.Method;
|
||||||
import org.jetbrains.asm4.signature.SignatureWriter;
|
|
||||||
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
import org.jetbrains.jet.codegen.binding.CalculatedClosure;
|
||||||
import org.jetbrains.jet.codegen.context.CodegenContext;
|
import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||||
import org.jetbrains.jet.codegen.context.LocalLookup;
|
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.signature.JvmMethodSignature;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationStateAware;
|
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.JetType;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.asm4.Opcodes.*;
|
import static org.jetbrains.asm4.Opcodes.*;
|
||||||
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
import static org.jetbrains.jet.codegen.AsmUtil.*;
|
||||||
import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
|
import static org.jetbrains.jet.codegen.CodegenUtil.isConst;
|
||||||
import static org.jetbrains.jet.codegen.FunctionTypesUtil.getFunctionImplClassName;
|
|
||||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
|
||||||
|
|
||||||
public class ClosureCodegen extends GenerationStateAware {
|
public class ClosureCodegen extends GenerationStateAware {
|
||||||
@@ -290,40 +291,22 @@ public class ClosureCodegen extends GenerationStateAware {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String getGenericSignature() {
|
private String getGenericSignature() {
|
||||||
SignatureWriter signatureWriter = new SignatureWriter();
|
ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor);
|
||||||
JvmClassName funClass = getFunctionImplClassName(funDescriptor);
|
Collection<JetType> supertypes = classDescriptor.getTypeConstructor().getSupertypes();
|
||||||
signatureWriter.visitClassType(funClass.getInternalName());
|
assert supertypes.size() == 1 : "Closure must have exactly one supertype: " + funDescriptor;
|
||||||
ReceiverParameterDescriptor receiverParameter = funDescriptor.getReceiverParameter();
|
JetType supertype = supertypes.iterator().next();
|
||||||
if (receiverParameter != null) {
|
|
||||||
appendType(signatureWriter, receiverParameter.getType(), '=');
|
|
||||||
}
|
|
||||||
for (ValueParameterDescriptor parameter : funDescriptor.getValueParameters()) {
|
|
||||||
appendType(signatureWriter, parameter.getType(), '=');
|
|
||||||
}
|
|
||||||
|
|
||||||
appendType(signatureWriter, funDescriptor.getReturnType(), '=');
|
BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true);
|
||||||
signatureWriter.visitEnd();
|
typeMapper.writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), sw);
|
||||||
|
sw.writeSupersStart();
|
||||||
|
sw.writeSuperclass();
|
||||||
|
typeMapper.mapType(supertype, sw, JetTypeMapperMode.TYPE_PARAMETER);
|
||||||
|
sw.writeSuperclassEnd();
|
||||||
|
sw.writeSupersEnd();
|
||||||
|
|
||||||
return signatureWriter.toString();
|
String signature = sw.makeJavaGenericSignature();
|
||||||
}
|
assert signature != null : "Closure superclass must have a generic signature: " + funDescriptor;
|
||||||
|
return signature;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) {
|
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.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
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 org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -85,13 +87,54 @@ public class FunctionTypesUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor funDescriptor, int arity) {
|
public static JetType getSuperTypeForClosure(@NotNull FunctionDescriptor descriptor, boolean kFunction) {
|
||||||
if (funDescriptor.getReceiverParameter() != null) {
|
int arity = descriptor.getValueParameters().size();
|
||||||
return EXTENSION_FUNCTIONS.get(arity).getDefaultType();
|
|
||||||
|
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 {
|
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
|
@NotNull
|
||||||
|
|||||||
+14
-6
@@ -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.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
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;
|
ClassDescriptor classDescriptor;
|
||||||
int arity = funDescriptor.getValueParameters().size();
|
|
||||||
|
|
||||||
classDescriptor = new ClassDescriptorImpl(
|
classDescriptor = new ClassDescriptorImpl(
|
||||||
funDescriptor.getContainingDeclaration(),
|
funDescriptor.getContainingDeclaration(),
|
||||||
@@ -92,7 +93,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
((ClassDescriptorImpl)classDescriptor).initialize(
|
((ClassDescriptorImpl)classDescriptor).initialize(
|
||||||
false,
|
false,
|
||||||
Collections.<TypeParameterDescriptor>emptyList(),
|
Collections.<TypeParameterDescriptor>emptyList(),
|
||||||
Collections.singleton(getSuperTypeForClosure(funDescriptor, arity)),
|
Collections.singleton(superType),
|
||||||
JetScope.EMPTY,
|
JetScope.EMPTY,
|
||||||
Collections.<ConstructorDescriptor>emptySet(),
|
Collections.<ConstructorDescriptor>emptySet(),
|
||||||
null,
|
null,
|
||||||
@@ -258,7 +259,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
if (functionDescriptor == null) return;
|
if (functionDescriptor == null) return;
|
||||||
|
|
||||||
String name = inventAnonymousClassName(expression);
|
String name = inventAnonymousClassName(expression);
|
||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
|
JetType superType = getSuperTypeForClosure(functionDescriptor, false);
|
||||||
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(functionLiteral, classDescriptor, name, true);
|
recordClosure(functionLiteral, classDescriptor, name, true);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
classStack.push(classDescriptor);
|
||||||
@@ -274,8 +276,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
// working around a problem with shallow analysis
|
// working around a problem with shallow analysis
|
||||||
if (functionDescriptor == null) return;
|
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);
|
String name = inventAnonymousClassName(expression);
|
||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(expression, classDescriptor, name, true);
|
recordClosure(expression, classDescriptor, name, true);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
classStack.push(classDescriptor);
|
||||||
@@ -326,7 +333,8 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String name = inventAnonymousClassName(function);
|
String name = inventAnonymousClassName(function);
|
||||||
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor);
|
JetType superType = getSuperTypeForClosure(functionDescriptor, false);
|
||||||
|
ClassDescriptor classDescriptor = recordClassForFunction(functionDescriptor, superType);
|
||||||
recordClosure(function, classDescriptor, name, true);
|
recordClosure(function, classDescriptor, name, true);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
classStack.push(classDescriptor);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
fun foo(s: String) {}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun bar(): String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.baz() {}
|
||||||
|
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val f = "${::foo}"
|
||||||
|
if (f != "jet.KFunctionImpl1<? super java.lang.String, ? extends jet.Unit>") return "Fail foo: $f"
|
||||||
|
|
||||||
|
val g = "${A::bar}"
|
||||||
|
if (g != "jet.KMemberFunctionImpl0<? super A, ? extends java.lang.String>") return "Fail bar: $f"
|
||||||
|
|
||||||
|
val h = "${A::baz}"
|
||||||
|
if (h != "jet.KExtensionFunctionImpl0<? super A, ? extends jet.Unit>") return "Fail baz: $h"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -6,22 +6,22 @@ fun check(expected: String, obj: Any?) {
|
|||||||
|
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
check("jet.FunctionImpl0<jet.Unit>")
|
check("jet.FunctionImpl0<? extends jet.Unit>")
|
||||||
{ () : Unit -> }
|
{ () : Unit -> }
|
||||||
check("jet.FunctionImpl0<java.lang.Integer>")
|
check("jet.FunctionImpl0<? extends java.lang.Integer>")
|
||||||
{ () : Int -> 42 }
|
{ () : Int -> 42 }
|
||||||
check("jet.FunctionImpl1<java.lang.String, java.lang.Long>")
|
check("jet.FunctionImpl1<? super java.lang.String, ? extends java.lang.Long>")
|
||||||
{ (s: String) : Long -> 42.toLong() }
|
{ (s: String) : Long -> 42.toLong() }
|
||||||
check("jet.FunctionImpl2<java.lang.Integer, java.lang.Integer, jet.Unit>")
|
check("jet.FunctionImpl2<? super java.lang.Integer, ? super java.lang.Integer, ? extends jet.Unit>")
|
||||||
{ (x: Int, y: Int) : Unit -> }
|
{ (x: Int, y: Int) : Unit -> }
|
||||||
|
|
||||||
check("jet.ExtensionFunctionImpl0<java.lang.Integer, jet.Unit>")
|
check("jet.ExtensionFunctionImpl0<? super java.lang.Integer, ? extends jet.Unit>")
|
||||||
{ Int.() : Unit -> }
|
{ Int.() : Unit -> }
|
||||||
check("jet.ExtensionFunctionImpl0<jet.Unit, java.lang.Integer>")
|
check("jet.ExtensionFunctionImpl0<? super jet.Unit, ? extends java.lang.Integer>")
|
||||||
{ Unit.() : Int -> 42 }
|
{ Unit.() : Int -> 42 }
|
||||||
check("jet.ExtensionFunctionImpl1<java.lang.String, java.lang.String, java.lang.Long>")
|
check("jet.ExtensionFunctionImpl1<? super java.lang.String, ? super java.lang.String, ? extends java.lang.Long>")
|
||||||
{ String.(s: String) : Long -> 42.toLong() }
|
{ String.(s: String) : Long -> 42.toLong() }
|
||||||
check("jet.ExtensionFunctionImpl2<java.lang.Integer, java.lang.Integer, java.lang.Integer, jet.Unit>")
|
check("jet.ExtensionFunctionImpl2<? super java.lang.Integer, ? super java.lang.Integer, ? super java.lang.Integer, ? extends jet.Unit>")
|
||||||
{ Int.(x: Int, y: Int) : Unit -> }
|
{ Int.(x: Int, y: Int) : Unit -> }
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|||||||
@@ -12,18 +12,20 @@ val unitFun = { }
|
|||||||
val intFun = { 42 }
|
val intFun = { 42 }
|
||||||
val stringParamFun = { (x: String) : Unit -> }
|
val stringParamFun = { (x: String) : Unit -> }
|
||||||
val listFun = { (l: List<String>) : List<String> -> l }
|
val listFun = { (l: List<String>) : List<String> -> l }
|
||||||
|
val mutableListFun = { (l: MutableList<Double>) : MutableList<Int> -> null!! }
|
||||||
|
|
||||||
val extensionFun = { Any.() : Unit -> }
|
val extensionFun = { Any.() : Unit -> }
|
||||||
val extensionWithArgFun = { Long.(x: Any) : Date -> Date() }
|
val extensionWithArgFun = { Long.(x: Any) : Date -> Date() }
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
assertGenericSuper("jet.FunctionImpl0<jet.Unit>", unitFun)
|
assertGenericSuper("jet.FunctionImpl0<? extends jet.Unit>", unitFun)
|
||||||
assertGenericSuper("jet.FunctionImpl0<java.lang.Integer>", intFun)
|
assertGenericSuper("jet.FunctionImpl0<? extends java.lang.Integer>", intFun)
|
||||||
assertGenericSuper("jet.FunctionImpl1<java.lang.String, jet.Unit>", stringParamFun)
|
assertGenericSuper("jet.FunctionImpl1<? super java.lang.String, ? extends jet.Unit>", stringParamFun)
|
||||||
assertGenericSuper("jet.FunctionImpl1<java.util.List, java.util.List>", listFun)
|
assertGenericSuper("jet.FunctionImpl1<? super java.util.List<? extends java.lang.String>, ? extends java.util.List<? extends java.lang.String>>", listFun)
|
||||||
|
assertGenericSuper("jet.FunctionImpl1<? super java.util.List<java.lang.Double>, ? extends java.util.List<java.lang.Integer>>", mutableListFun)
|
||||||
|
|
||||||
assertGenericSuper("jet.ExtensionFunctionImpl0<java.lang.Object, jet.Unit>", extensionFun)
|
assertGenericSuper("jet.ExtensionFunctionImpl0<? super java.lang.Object, ? extends jet.Unit>", extensionFun)
|
||||||
assertGenericSuper("jet.ExtensionFunctionImpl1<java.lang.Long, java.lang.Object, java.util.Date>", extensionWithArgFun)
|
assertGenericSuper("jet.ExtensionFunctionImpl1<? super java.lang.Long, ? super java.lang.Object, ? extends java.util.Date>", extensionWithArgFun)
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -564,6 +564,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest("compiler/testData/codegen/box/callableReference/sortListOfStrings.kt");
|
doTest("compiler/testData/codegen/box/callableReference/sortListOfStrings.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("toString.kt")
|
||||||
|
public void testToString() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/callableReference/toString.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("topLevelFromClass.kt")
|
@TestMetadata("topLevelFromClass.kt")
|
||||||
public void testTopLevelFromClass() throws Exception {
|
public void testTopLevelFromClass() throws Exception {
|
||||||
doTest("compiler/testData/codegen/box/callableReference/topLevelFromClass.kt");
|
doTest("compiler/testData/codegen/box/callableReference/topLevelFromClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user