diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java index f2cb8838b1d..ab2d5de350d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -1,12 +1,17 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.codegen.signature.JetSignatureWriter; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureAdapter; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureWriter; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.util.CheckSignatureAdapter; +import java.util.ArrayList; +import java.util.List; import java.util.Stack; /** @@ -27,13 +32,31 @@ public class BothSignatureWriter { this.asmType = asmType; } } + + private enum State { + START, + TYPE_PARAMETERS, + + PARAMETERS, + RETURN_TYPE, + METHOD_END, + + SUPERS, + CLASS_END, + } private final SignatureWriter signatureWriter = new SignatureWriter(); private final SignatureVisitor signatureVisitor; - private final JetSignatureWriter jetSignatureWriter = new JetSignatureWriter(); + private JetSignatureWriter jetSignatureWriter; + + private String kotlinClassSignature; + + private List kotlinParameterTypes = new ArrayList(); + private String kotlinReturnType; private final Mode mode; + private State state = State.START; public BothSignatureWriter(Mode mode) { this.mode = mode; @@ -76,20 +99,37 @@ public class BothSignatureWriter { } } } + + private void checkState(State state) { + if (DEBUG_SIGNATURE_WRITER) { + if (state != this.state) { + throw new IllegalStateException(); + } + if (jetSignatureWriter != null) { + throw new IllegalStateException(); + } + checkTopLevel(); + } + } + + private void transitionState(State from, State to) { + checkState(from); + state = to; + } /** * Shortcut */ - public void writeAsmType(Type asmType) { + public void writeAsmType(Type asmType, boolean nullable) { switch (asmType.getSort()) { case Type.OBJECT: - writeClassBegin(asmType.getInternalName()); + writeClassBegin(asmType.getInternalName(), nullable); writeClassEnd(); return; case Type.ARRAY: - writeArrayType(); - writeAsmType(asmType.getElementType()); + writeArrayType(nullable); + writeAsmType(asmType.getElementType(), false); writeArrayEnd(); return; default: @@ -97,20 +137,31 @@ public class BothSignatureWriter { if (descriptor.length() != 1) { throw new IllegalStateException(); } - signatureVisitor().visitBaseType(descriptor.charAt(0)); + writeBaseType(descriptor.charAt(0), nullable); } } - - public void writeClassBegin(String internalName) { + + private void writeBaseType(char c, boolean nullable) { + if (nullable) { + throw new IllegalStateException(); + } + signatureVisitor().visitBaseType(c); + jetSignatureWriter.visitBaseType(c, nullable); + } + + public void writeClassBegin(String internalName, boolean nullable) { signatureVisitor().visitClassType(internalName); + jetSignatureWriter.visitClassType(internalName, nullable); } public void writeClassEnd() { signatureVisitor().visitEnd(); + jetSignatureWriter.visitEnd(); } - public void writeArrayType() { + public void writeArrayType(boolean nullable) { push(signatureVisitor().visitArrayType()); + jetSignatureWriter.visitArrayType(nullable); } public void writeArrayEnd() { @@ -119,24 +170,39 @@ public class BothSignatureWriter { public void writeTypeArgument(char c) { push(signatureVisitor().visitTypeArgument(c)); + jetSignatureWriter.visitTypeArgument(c); } public void writeTypeArgumentEnd() { pop(); } - public void writeTypeVariable(final String name) { + public void writeTypeVariable(final String name, boolean nullable) { signatureVisitor().visitTypeVariable(name); + jetSignatureWriter.visitTypeVariable(name, nullable); } public void writeFormalTypeParameter(final String name) { checkTopLevel(); signatureVisitor().visitFormalTypeParameter(name); + jetSignatureWriter.visitFormalTypeParameter(name); + } + + public void writerFormalTypeParametersStart() { + checkTopLevel(); + transitionState(State.START, State.TYPE_PARAMETERS); + jetSignatureWriter = new JetSignatureWriter(); + } + + public void writeFormalTypeParametersEnd() { + jetSignatureWriter = null; + checkState(State.TYPE_PARAMETERS); } public void writeClassBound() { push(signatureVisitor().visitClassBound()); + jetSignatureWriter.visitClassBound(); } public void writeClassBoundEnd() { @@ -145,33 +211,75 @@ public class BothSignatureWriter { public void writeInterfaceBound() { push(signatureVisitor().visitInterfaceBound()); + jetSignatureWriter.visitInterfaceBound(); } public void writeInterfaceBoundEnd() { pop(); } + + public void writeParametersStart() { + transitionState(State.TYPE_PARAMETERS, State.PARAMETERS); + } + + public void writeParametersEnd() { + checkState(State.PARAMETERS); + } public void writeParameterType() { push(signatureVisitor().visitParameterType()); + jetSignatureWriter = new JetSignatureWriter(); + //jetSignatureWriter.visitParameterType(); } public void writeParameterTypeEnd() { pop(); + String signature = jetSignatureWriter.toString(); + kotlinParameterTypes.add(signature); + + if (DEBUG_SIGNATURE_WRITER) { + new JetSignatureReader(signature).acceptTypeOnly(new JetSignatureAdapter()); + } + + jetSignatureWriter = null; } public void writeReturnType() { + transitionState(State.PARAMETERS, State.RETURN_TYPE); + + jetSignatureWriter = new JetSignatureWriter(); + push(signatureVisitor().visitReturnType()); + //jetSignatureWriter.visitReturnType(); } public void writeReturnTypeEnd() { pop(); + + kotlinReturnType = jetSignatureWriter.toString(); + + if (DEBUG_SIGNATURE_WRITER) { + new JetSignatureReader(kotlinReturnType).acceptTypeOnly(new JetSignatureAdapter()); + } + + jetSignatureWriter = null; + transitionState(State.RETURN_TYPE, State.METHOD_END); + } + + public void writeSupersStart() { + transitionState(State.TYPE_PARAMETERS, State.SUPERS); + jetSignatureWriter = new JetSignatureWriter(); + } + + public void writeSupersEnd() { + kotlinClassSignature = jetSignatureWriter.toString(); + jetSignatureWriter = null; + transitionState(State.SUPERS, State.CLASS_END); } public void writeSuperclass() { - checkTopLevel(); - checkMode(Mode.CLASS); - push(signatureVisitor().visitSuperclass()); + jetSignatureWriter.visitSuperclass(); } public void writeSuperclassEnd() { @@ -186,6 +294,7 @@ public class BothSignatureWriter { checkMode(Mode.CLASS); push(signatureVisitor().visitInterface()); + jetSignatureWriter.visitInterface(); } public void writeInterfaceEnd() { @@ -200,16 +309,31 @@ public class BothSignatureWriter { @Nullable public String makeJavaString() { - if (!visitors.isEmpty()) { + if (state != State.METHOD_END && state != State.CLASS_END) { throw new IllegalStateException(); } + checkTopLevel(); + // TODO: return null if not generic return signatureWriter.toString(); } + @NotNull + public List makeKotlinSignatures() { + checkState(State.METHOD_END); + // TODO: return nulls if equal to #makeJavaString + return kotlinParameterTypes; + } + @Nullable - public String makeKotlinString() { - // TODO: not implemented yet - return null; + public String makeKotlinReturnTypeSignature() { + checkState(State.METHOD_END); + return kotlinReturnType; + } + + @Nullable + public String makeKotlinClassSignature() { + checkState(State.CLASS_END); + return kotlinClassSignature; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 46bd9a3ad45..75e3d28323a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -53,7 +53,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { public static CallableMethod asCallableMethod(FunctionDescriptor fd) { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); - final CallableMethod result = new CallableMethod(owner, new JvmMethodSignature(descriptor, null), INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + final CallableMethod result = new CallableMethod(owner, new JvmMethodSignature(descriptor, null, null, null), INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(fd); } @@ -165,7 +165,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); - fc.generateMethod(body, new JvmMethodSignature(invokeSignature(funDescriptor), null), funDescriptor); + fc.generateMethod(body, new JvmMethodSignature(invokeSignature(funDescriptor), null, null, null), funDescriptor); return closureContext.outerWasUsed; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index ab951d0e173..27cea25ce10 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -90,6 +90,9 @@ public class FunctionCodegen { if(functionDescriptor.getReturnType().isNullable()) { av.visit(StdlibNames.JET_METHOD_NULLABLE_RETURN_TYPE_FIELD, true); } + if (jvmSignature.getKotlinReturnType() != null) { + av.visit(StdlibNames.JET_METHOD_RETURN_TYPE_FIELD, jvmSignature.getKotlinReturnType()); + } av.visitEnd(); } @@ -121,6 +124,9 @@ public class FunctionCodegen { if(parameterDescriptor.getOutType().isNullable()) { av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } + if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) { + av.visit(StdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD, jvmSignature.getKotlinParameterTypes().get(i)); + } av.visitEnd(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 421ad544fe4..cd89380cbf5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -61,7 +61,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ? Opcodes.ACC_INTERFACE : 0/*Opcodes.ACC_SUPER*/), signature.getName(), - signature.getGenericSignature(), + signature.getJavaGenericSignature(), signature.getSuperclassName(), signature.getInterfaces().toArray(new String[0]) ); @@ -77,57 +77,55 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { annotationVisitor.visitEnd(); } } - + private JvmClassSignature signature() { - String genericSignature; List superInterfaces; - { - LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); + LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); - BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); - { // type parameters - List typeParameters = descriptor.getTypeConstructor().getParameters(); - typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); - } - - - { // superclass - signatureVisitor.writeSuperclass(); - if (superClassType == null) { - signatureVisitor.writeClassBegin(superClass); - signatureVisitor.writeClassEnd(); - } else { - typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); - } - signatureVisitor.writeSuperclassEnd(); - } - - - { // superinterfaces - superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); - - for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { - JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); - assert superType != null; - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - if (CodegenUtil.isInterface(superClassDescriptor)) { - signatureVisitor.writeInterface(); - Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); - signatureVisitor.writeInterfaceEnd(); - superInterfacesLinkedHashSet.add(jvmName.getInternalName()); - } - } - - superInterfaces = new ArrayList(superInterfacesLinkedHashSet); - } - - // TODO: null if class is not generic and does not have generic superclasses - genericSignature = signatureVisitor.makeJavaString(); + { // type parameters + List typeParameters = descriptor.getTypeConstructor().getParameters(); + typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); } - return new JvmClassSignature(jvmName(), superClass, superInterfaces, genericSignature); + + signatureVisitor.writeSupersStart(); + + { // superclass + signatureVisitor.writeSuperclass(); + if (superClassType == null) { + signatureVisitor.writeClassBegin(superClass, false); + signatureVisitor.writeClassEnd(); + } else { + typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + } + signatureVisitor.writeSuperclassEnd(); + } + + + { // superinterfaces + superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.isInterface(superClassDescriptor)) { + signatureVisitor.writeInterface(); + Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + signatureVisitor.writeInterfaceEnd(); + superInterfacesLinkedHashSet.add(jvmName.getInternalName()); + } + } + + superInterfaces = new ArrayList(superInterfacesLinkedHashSet); + } + + signatureVisitor.writeSupersEnd(); + + return new JvmClassSignature(jvmName(), superClass, superInterfaces, signatureVisitor.makeJavaString(), signatureVisitor.makeKotlinClassSignature()); } private String jvmName() { @@ -324,7 +322,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } constructorMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - callableMethod = new CallableMethod("", new JvmMethodSignature(constructorMethod, null) /* TODO */, Opcodes.INVOKESPECIAL, Collections.emptyList()); + callableMethod = new CallableMethod("", new JvmMethodSignature(constructorMethod, null, null, null) /* TODO */, Opcodes.INVOKESPECIAL, Collections.emptyList()); } else { callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index d09e0480f0b..58a60e131b6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -165,13 +165,13 @@ public class JetTypeMapper { @NotNull private Type mapReturnType(final JetType jetType, @Nullable BothSignatureWriter signatureVisitor) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { if (signatureVisitor != null) { - signatureVisitor.writeAsmType(Type.VOID_TYPE); + signatureVisitor.writeAsmType(Type.VOID_TYPE, false); } return Type.VOID_TYPE; } if (jetType.equals(JetStandardClasses.getNullableNothingType())) { if (signatureVisitor != null) { - visitAsmType(signatureVisitor, TYPE_OBJECT); + visitAsmType(signatureVisitor, TYPE_OBJECT, false); } return TYPE_OBJECT; } @@ -257,7 +257,7 @@ public class JetTypeMapper { JetType memberType = jetType.getArguments().get(0).getType(); if (signatureVisitor != null) { - signatureVisitor.writeArrayType(); + signatureVisitor.writeArrayType(jetType.isNullable()); mapType(memberType, kind, signatureVisitor, true); signatureVisitor.writeArrayEnd(); } @@ -271,7 +271,7 @@ public class JetTypeMapper { if (JetStandardClasses.getAny().equals(descriptor)) { if (signatureVisitor != null) { - visitAsmType(signatureVisitor, TYPE_OBJECT); + visitAsmType(signatureVisitor, TYPE_OBJECT, jetType.isNullable()); } return TYPE_OBJECT; } @@ -282,7 +282,7 @@ public class JetTypeMapper { Type asmType = Type.getObjectType(name + (kind == OwnerKind.TRAIT_IMPL ? "$$TImpl" : "")); if (signatureVisitor != null) { - signatureVisitor.writeClassBegin(asmType.getInternalName()); + signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable()); for (TypeProjection proj : jetType.getArguments()) { // TODO: +- signatureVisitor.writeTypeArgument('='); @@ -298,7 +298,7 @@ public class JetTypeMapper { if (descriptor instanceof TypeParameterDescriptor) { if (signatureVisitor != null) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) jetType.getConstructor().getDeclarationDescriptor(); - signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName()); + signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable()); } return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); @@ -310,16 +310,16 @@ public class JetTypeMapper { private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor, boolean genericTypeParameter) { if (signatureVisitor != null) { if (genericTypeParameter) { - visitAsmType(signatureVisitor, boxType(asmType)); + visitAsmType(signatureVisitor, boxType(asmType), jetType.isNullable()); } else { - visitAsmType(signatureVisitor, asmType); + visitAsmType(signatureVisitor, asmType, jetType.isNullable()); } } return asmType; } - public static void visitAsmType(BothSignatureWriter visitor, Type asmType) { - visitor.writeAsmType(asmType); + public static void visitAsmType(BothSignatureWriter visitor, Type asmType, boolean nullable) { + visitor.writeAsmType(asmType, nullable); } public static Type unboxType(final Type type) { @@ -469,12 +469,16 @@ public class JetTypeMapper { signatureVisitor.writeParameterTypeEnd(); } } + if (signatureVisitor != null) { + signatureVisitor.writeParametersStart(); + } + for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { parameterTypes.add(TYPE_TYPEINFO); if (signatureVisitor != null) { signatureVisitor.writeParameterType(); - visitAsmType(signatureVisitor, TYPE_TYPEINFO); + visitAsmType(signatureVisitor, TYPE_TYPEINFO, false); signatureVisitor.writeParameterTypeEnd(); } } @@ -490,12 +494,17 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } + + if (signatureVisitor != null) { + signatureVisitor.writeParametersEnd(); + } + Type returnType; if (f instanceof ConstructorDescriptor) { returnType = Type.VOID_TYPE; if (signatureVisitor != null) { signatureVisitor.writeReturnType(); - visitAsmType(signatureVisitor, Type.VOID_TYPE); + visitAsmType(signatureVisitor, Type.VOID_TYPE, false); signatureVisitor.writeReturnTypeEnd(); } } else { @@ -509,7 +518,12 @@ public class JetTypeMapper { } } Method method = new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, signatureVisitor != null ? signatureVisitor.makeJavaString() : null); + if (signatureVisitor == null) { + return new JvmMethodSignature(method, null, null, null); + } else { + return new JvmMethodSignature(method, signatureVisitor.makeJavaString(), + signatureVisitor.makeKotlinSignatures(), signatureVisitor.makeKotlinReturnTypeSignature()); + } } @@ -518,9 +532,11 @@ public class JetTypeMapper { return; } + signatureVisitor.writerFormalTypeParametersStart(); for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); } + signatureVisitor.writeFormalTypeParametersEnd(); } private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) { @@ -567,7 +583,7 @@ public class JetTypeMapper { } Type returnType = mapReturnType(f.getReturnType()); // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])), null); + return new JvmMethodSignature(new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])), null, null, null); } @@ -592,7 +608,7 @@ public class JetTypeMapper { } // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, returnType, params.toArray(new Type[params.size()])), null); + return new JvmMethodSignature(new Method(name, returnType, params.toArray(new Type[params.size()])), null, null, null); } @Nullable @@ -622,7 +638,7 @@ public class JetTypeMapper { params.add(mapType(inType)); // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, Type.VOID_TYPE, params.toArray(new Type[params.size()])), null); + return new JvmMethodSignature(new Method(name, Type.VOID_TYPE, params.toArray(new Type[params.size()])), null, null, null); } private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, List valueParameterTypes) { @@ -644,7 +660,7 @@ public class JetTypeMapper { } Method method = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, null); // TODO: generics signature + return new JvmMethodSignature(method, null, null, null); // TODO: generics signature } public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java index e866f873f8a..4eeeaf10542 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java @@ -1,5 +1,8 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.util.List; /** @@ -9,13 +12,16 @@ public class JvmClassSignature { private final String name; private final String superclassName; private final List interfaces; - private final String genericSignature; + private final String javaGenericSignature; + private final String kotlinGenericSignature; - public JvmClassSignature(String name, String superclassName, List interfaces, String genericSignature) { + public JvmClassSignature(String name, String superclassName, List interfaces, + @Nullable String javaGenericSignature, @Nullable String kotlinGenericSignature) { this.name = name; this.superclassName = superclassName; this.interfaces = interfaces; - this.genericSignature = genericSignature; + this.javaGenericSignature = javaGenericSignature; + this.kotlinGenericSignature = kotlinGenericSignature; } public String getName() { @@ -30,7 +36,11 @@ public class JvmClassSignature { return interfaces; } - public String getGenericSignature() { - return genericSignature; + public String getJavaGenericSignature() { + return javaGenericSignature; + } + + public String getKotlinGenericSignature() { + return kotlinGenericSignature; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java index 2dd2395c4fd..6eda7035501 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java @@ -4,6 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.commons.Method; +import java.util.List; + /** * @author Stepan Koltsov */ @@ -12,10 +14,16 @@ public class JvmMethodSignature { private final Method asmMethod; /** Null when we don't care about type parameters */ private final String genericsSignature; + // TODO: type parameters + private final List kotlinParameterTypes; + private final String kotlinReturnType; - public JvmMethodSignature(@NotNull Method asmMethod, @Nullable String genericsSignature) { + public JvmMethodSignature(@NotNull Method asmMethod, @Nullable String genericsSignature, + @Nullable List kotlinParameterTypes, @Nullable String kotlinReturnType) { this.asmMethod = asmMethod; this.genericsSignature = genericsSignature; + this.kotlinParameterTypes = kotlinParameterTypes; + this.kotlinReturnType = kotlinReturnType; } public Method getAsmMethod() { @@ -25,4 +33,12 @@ public class JvmMethodSignature { public String getGenericsSignature() { return genericsSignature; } + + public List getKotlinParameterTypes() { + return kotlinParameterTypes; + } + + public String getKotlinReturnType() { + return kotlinReturnType; + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index d74c6aafd28..b70626a96a7 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -360,6 +360,7 @@ public class JavaDescriptorResolver { boolean changeNullable = false; boolean nullable = true; + String typeFromAnnotation = null; // TODO: must be very slow, make it lazy? String name = parameter.getName() != null ? parameter.getName() : "p" + i; @@ -383,10 +384,20 @@ public class JavaDescriptorResolver { nullable = false; changeNullable = true; } + + PsiLiteralExpression signatureExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD); + if (signatureExpression != null) { + typeFromAnnotation = (String) signatureExpression.getValue(); + } } } - JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); + JetType outType; + if (typeFromAnnotation != null) { + outType = semanticServices.getTypeTransformer().transformToType(typeFromAnnotation); + } else { + outType = semanticServices.getTypeTransformer().transformToType(psiType); + } return new ValueParameterDescriptorImpl( containingDeclaration, i, @@ -509,6 +520,8 @@ public class JavaDescriptorResolver { private JetType makeReturnType(PsiType returnType, PsiMethod method) { boolean changeNullable = false; boolean nullable = true; + + String returnTypeFromAnnotation = null; for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) { if (annotation.getQualifiedName().equals(StdlibNames.JET_METHOD_CLASS)) { @@ -520,9 +533,19 @@ public class JavaDescriptorResolver { nullable = false; changeNullable = true; } + + PsiLiteralExpression returnTypeExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_METHOD_RETURN_TYPE_FIELD); + if (returnTypeExpression != null) { + returnTypeFromAnnotation = (String) returnTypeExpression.getValue(); + } } } - JetType transformedType = semanticServices.getTypeTransformer().transformToType(returnType); + JetType transformedType; + if (returnTypeFromAnnotation != null) { + transformedType = semanticServices.getTypeTransformer().transformToType(returnTypeFromAnnotation); + } else { + transformedType = semanticServices.getTypeTransformer().transformToType(returnType); + } if (changeNullable) { return TypeUtils.makeNullableAsSpecified(transformedType, nullable); } else { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java index 3f19264e915..82d25433ac1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -6,6 +6,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor; import org.jetbrains.jet.lang.types.*; import java.util.Collections; @@ -57,6 +59,19 @@ public class JavaTypeTransformer { return result; } + @NotNull + public JetType transformToType(@NotNull String kotlinSignature) { + final JetType[] r = new JetType[1]; + JetTypeJetSignatureReader reader = new JetTypeJetSignatureReader(resolver, standardLibrary) { + @Override + protected void done(@NotNull JetType jetType) { + r[0] = jetType; + } + }; + new JetSignatureReader(kotlinSignature).acceptType(reader); + return r[0]; + } + @NotNull public JetType transformToType(@NotNull PsiType javaType) { return javaType.accept(new PsiTypeVisitor() { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java new file mode 100644 index 00000000000..0e0819d8f7a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java @@ -0,0 +1,196 @@ +package org.jetbrains.jet.lang.resolve.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +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.Variance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Stepan Koltsov + */ +public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor { + + private final JavaDescriptorResolver javaDescriptorResolver; + private final JetStandardLibrary jetStandardLibrary; + + public JetTypeJetSignatureReader(JavaDescriptorResolver javaDescriptorResolver, JetStandardLibrary jetStandardLibrary) { + this.javaDescriptorResolver = javaDescriptorResolver; + this.jetStandardLibrary = jetStandardLibrary; + } + + + + @Override + public void visitFormalTypeParameter(String name) { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitClassBound() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitInterfaceBound() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitSuperclass() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitInterface() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitParameterType() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitReturnType() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitExceptionType() { + throw new IllegalStateException(); + } + + private JetType getPrimitiveType(char descriptor, boolean nullable) { + if (!nullable) { + switch (descriptor) { + case 'Z': + return jetStandardLibrary.getBooleanType(); + case 'C': + return jetStandardLibrary.getCharType(); + case 'B': + return jetStandardLibrary.getByteType(); + case 'S': + return jetStandardLibrary.getShortType(); + case 'I': + return jetStandardLibrary.getIntType(); + case 'F': + return jetStandardLibrary.getFloatType(); + case 'J': + return jetStandardLibrary.getLongType(); + case 'D': + return jetStandardLibrary.getDoubleType(); + case 'V': + return JetStandardClasses.getUnitType(); + } + } else { + switch (descriptor) { + case 'Z': + return jetStandardLibrary.getNullableBooleanType(); + case 'C': + return jetStandardLibrary.getNullableCharType(); + case 'B': + return jetStandardLibrary.getNullableByteType(); + case 'S': + return jetStandardLibrary.getNullableShortType(); + case 'I': + return jetStandardLibrary.getNullableIntType(); + case 'F': + return jetStandardLibrary.getNullableFloatType(); + case 'J': + return jetStandardLibrary.getNullableLongType(); + case 'D': + return jetStandardLibrary.getNullableDoubleType(); + case 'V': + throw new IllegalStateException("incorrect signature: nullable void"); + } + } + throw new IllegalStateException("incorrect signature"); + } + + @Override + public void visitBaseType(char descriptor, boolean nullable) { + done(getPrimitiveType(descriptor, nullable)); + } + + @Override + public void visitTypeVariable(String name, boolean nullable) { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitArrayType(boolean nullable) { + throw new IllegalStateException(); + } + + + private ClassDescriptor classDescriptor; + private boolean nullable; + private List typeArguments; + + @Override + public void visitClassType(String name, boolean nullable) { + String ourName = name.replace('/', '.'); + this.classDescriptor = javaDescriptorResolver.resolveClass(ourName); + if (this.classDescriptor == null) { + throw new IllegalStateException("class not found by name: " + ourName); // TODO: wrong exception + } + this.nullable = nullable; + this.typeArguments = new ArrayList(); + } + + @Override + public void visitInnerClassType(String name, boolean nullable) { + throw new IllegalStateException(); + } + + @Override + public void visitTypeArgument() { + throw new IllegalStateException(); + } + + private static Variance parseVariance(char wildcard) { + switch (wildcard) { + case '=': return Variance.INVARIANT; + case '+': return Variance.OUT_VARIANCE; + case '-': return Variance.IN_VARIANCE; + default: throw new IllegalStateException(); + } + } + + @Override + public JetSignatureVisitor visitTypeArgument(final char wildcard) { + return new JetTypeJetSignatureReader(javaDescriptorResolver, jetStandardLibrary) { + + @Override + protected void done(@NotNull JetType jetType) { + typeArguments.add(new TypeProjection(parseVariance(wildcard), jetType)); + } + }; + } + + @Override + public void visitEnd() { + JetType jetType = new JetTypeImpl( + Collections.emptyList(), + classDescriptor.getTypeConstructor(), + nullable, + typeArguments, + ErrorUtils.getErrorScope()); + done(jetType); + } + + protected abstract void done(@NotNull JetType jetType); +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java index 214be7c888d..c6223502385 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -13,6 +13,7 @@ public class StdlibNames { public static final String JET_VALUE_PARAMETER_NAME_FIELD = "name"; public static final String JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue"; public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable"; + public static final String JET_VALUE_PARAMETER_TYPE_FIELD = "type"; public static final String JET_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter"; @@ -25,6 +26,7 @@ public class StdlibNames { public static final String JET_METHOD_DESCRIPTOR = "Ljet/typeinfo/JetMethod;"; public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; + public static final String JET_METHOD_RETURN_TYPE_FIELD = "returnType"; public static final String JET_OBJECT_INTERNAL = "jet/JetObject"; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java new file mode 100644 index 00000000000..5f9d10245b0 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java @@ -0,0 +1,79 @@ +package org.jetbrains.jet.lang.resolve.java.signature; + +/** + * @author Stepan Koltsov + */ +public class JetSignatureAdapter implements JetSignatureVisitor { + @Override + public void visitFormalTypeParameter(String name) { + } + + @Override + public JetSignatureVisitor visitClassBound() { + return this; + } + + @Override + public JetSignatureVisitor visitInterfaceBound() { + return this; + } + + @Override + public JetSignatureVisitor visitSuperclass() { + return this; + } + + @Override + public JetSignatureVisitor visitInterface() { + return this; + } + + @Override + public JetSignatureVisitor visitParameterType() { + return this; + } + + @Override + public JetSignatureVisitor visitReturnType() { + return this; + } + + @Override + public JetSignatureVisitor visitExceptionType() { + return this; + } + + @Override + public void visitBaseType(char descriptor, boolean nullable) { + } + + @Override + public void visitTypeVariable(String name, boolean nullable) { + } + + @Override + public JetSignatureVisitor visitArrayType(boolean nullable) { + return this; + } + + @Override + public void visitClassType(String name, boolean nullable) { + } + + @Override + public void visitInnerClassType(String name, boolean nullable) { + } + + @Override + public void visitTypeArgument() { + } + + @Override + public JetSignatureVisitor visitTypeArgument(char wildcard) { + return this; + } + + @Override + public void visitEnd() { + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java similarity index 93% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java index 6485efde6bf..cbdebb01b3a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; @@ -60,6 +60,17 @@ public class JetSignatureReader { } } + public int acceptType(JetSignatureVisitor v) { + return parseType(this.signature, 0, v); + } + + public void acceptTypeOnly(JetSignatureVisitor v) { + int r = acceptType(v); + if (r != signature.length()) { + throw new IllegalStateException(); + } + } + private static int parseType( final String signature, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java similarity index 98% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java index 04e1319dd03..e353dd6dbb3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureVisitor; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java similarity index 98% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java index b85d48b3ecc..7e1a7837a08 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureWriter; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index ee76f1ed2e9..2025559fc74 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -95,7 +95,7 @@ public class ErrorUtils { true, Collections.emptyList(), Collections.emptyList(), getErrorScope(), ERROR_CONSTRUCTOR_GROUP, ERROR_CONSTRUCTOR); } - private static JetScope getErrorScope() { + public static JetScope getErrorScope() { return ERROR_SCOPE; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java index 4e1fd0d08cd..c8bc340d8bb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java @@ -21,7 +21,7 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType { private final boolean nullable; private JetScope memberScope; - public JetTypeImpl(List annotations, TypeConstructor constructor, boolean nullable, List arguments, JetScope memberScope) { + public JetTypeImpl(List annotations, TypeConstructor constructor, boolean nullable, @NotNull List arguments, JetScope memberScope) { super(annotations); this.constructor = constructor; this.nullable = nullable; diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 7a0fa933747..b7ceb359a44 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -158,7 +158,7 @@ public class ReadClassDataTest extends UsefulTestCase { for (int i = 0; i < a.getValueParameters().size(); ++i) { compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); } - Assert.assertEquals(a.getReturnType(), b.getReturnType()); + compareTypes(a.getReturnType(), b.getReturnType()); System.out.println("fun " + a.getName() + "(...): " + a.getReturnType()); } diff --git a/stdlib/src/jet/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java index edc2199a870..b057014caf2 100644 --- a/stdlib/src/jet/typeinfo/JetMethod.java +++ b/stdlib/src/jet/typeinfo/JetMethod.java @@ -26,4 +26,9 @@ public @interface JetMethod { * @return is this type returnTypeNullable */ boolean nullableReturnType() default false; + + /** + * Return type type unless java type is correct Kotlin type. + */ + String returnType () default ""; } diff --git a/stdlib/src/jet/typeinfo/JetValueParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java index 3a0a2992ad4..db0a4f52605 100644 --- a/stdlib/src/jet/typeinfo/JetValueParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -34,4 +34,9 @@ public @interface JetValueParameter { * @return if this parameter has default value */ boolean hasDefaultValue () default false; + + /** + * @return type unless Java type is correct Kotlin type. + */ + String type() default ""; }