diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index 11c1bf1c810..a5d3447e98c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -124,15 +124,17 @@ public abstract class CodegenContext { return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName); } - public FrameMap prepareFrame() { + public FrameMap prepareFrame(JetTypeMapper mapper) { FrameMap frameMap = new FrameMap(); if (getContextKind() != OwnerKind.NAMESPACE) { frameMap.enterTemp(); // 0 slot for this } - if (getReceiverDescriptor() != null) { - frameMap.enterTemp(); // Next slot for fake this + CallableDescriptor receiverDescriptor = getReceiverDescriptor(); + if (receiverDescriptor != null) { + Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType()); + frameMap.enterTemp(type.getSize()); // Next slot for fake this } return frameMap; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 27d971944dd..857765785c8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -4,6 +4,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.resolve.DescriptorRenderer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; @@ -26,17 +27,19 @@ public class FunctionCodegen { private final CodegenContext owner; private final ClassBuilder v; private final GenerationState state; + private final JetTypeMapper typeMapper; public FunctionCodegen(CodegenContext owner, ClassBuilder v, GenerationState state) { this.owner = owner; this.v = v; this.state = state; + typeMapper = state.getTypeMapper(); } public void gen(JetNamedFunction f) { final FunctionDescriptor functionDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, f); assert functionDescriptor != null; - Method method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false, owner.getContextKind()).getSignature(); + Method method = typeMapper.mapToCallableMethod(functionDescriptor, false, owner.getContextKind()).getSignature(); generateMethod(f, method, functionDescriptor); } @@ -59,21 +62,57 @@ public class FunctionCodegen { OwnerKind kind = context.getContextKind(); + ReceiverDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject(); + ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); + if (kind != OwnerKind.TRAIT_IMPL || bodyExpressions != null) { + boolean isStatic = kind == OwnerKind.NAMESPACE; + if (isStatic || kind == OwnerKind.TRAIT_IMPL) + flags |= ACC_STATIC; - boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL; - if (isStatic) flags |= ACC_STATIC; - - boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration())); + boolean isAbstract = !isStatic && !(kind == OwnerKind.TRAIT_IMPL) && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration())); if (isAbstract) flags |= ACC_ABSTRACT; final MethodVisitor mv = v.newMethod(fun, flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null); - if(kind != OwnerKind.TRAIT_IMPL && v.generateCode()) { - int start = functionDescriptor.getReceiverParameter().exists() ? 1 : 0; + if(v.generateCode()) { + int start = 0; + if(kind != OwnerKind.TRAIT_IMPL) { + AnnotationVisitor av = mv.visitAnnotation("Ljet/typeinfo/JetMethod;", true); + if(functionDescriptor.getReturnType().isNullable()) { + av.visit("nullableReturnType", true); + } + av.visitEnd(); + } + + if(kind == OwnerKind.TRAIT_IMPL) { + AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetParameter;", true); + av.visit("value", "this$self"); + av.visitEnd(); + } + if(receiverParameter.exists()) { + AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetParameter;", true); + av.visit("value", "this$receiver"); + if(receiverParameter.getType().isNullable()) { + av.visit("nullable", true); + } + av.visitEnd(); + } + for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + AnnotationVisitor av = mv.visitParameterAnnotation(start++, "Ljet/typeinfo/JetTypeParameter;", true); + av.visit("value", typeParameterDescriptor.getName()); + av.visitEnd(); + } for(int i = 0; i != paramDescrs.size(); ++i) { - AnnotationVisitor annotationVisitor = mv.visitParameterAnnotation(i + start, "Ljet/typeinfo/JetParameterName;", true); - annotationVisitor.visit("value", paramDescrs.get(i).getName()); - annotationVisitor.visitEnd(); + AnnotationVisitor av = mv.visitParameterAnnotation(i + start, "Ljet/typeinfo/JetParameter;", true); + ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); + av.visit("value", parameterDescriptor.getName()); + if(parameterDescriptor.hasDefaultValue()) { + av.visit("hasDefaultValue", true); + } + if(parameterDescriptor.getOutType().isNullable()) { + av.visit("nullable", true); + } + av.visitEnd(); } } if (!isAbstract && v.generateCode()) { @@ -82,12 +121,18 @@ public class FunctionCodegen { Label methodBegin = new Label(); mv.visitLabel(methodBegin); - FrameMap frameMap = context.prepareFrame(); + FrameMap frameMap = context.prepareFrame(typeMapper); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), context, state); Type[] argTypes = jvmSignature.getArgumentTypes(); - int add = functionDescriptor.getReceiverParameter().exists() ? state.getTypeMapper().mapType(functionDescriptor.getReceiverParameter().getType()).getSize() : 0; + int add = 0; + + if(kind == OwnerKind.TRAIT_IMPL) + add++; + + if(receiverParameter.exists()) + add++; for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { int slot = frameMap.enterTemp(); @@ -114,9 +159,9 @@ public class FunctionCodegen { } else { for (ValueParameterDescriptor parameter : paramDescrs) { - Type sharedVarType = state.getTypeMapper().getSharedVarType(parameter); - Type localVarType = state.getTypeMapper().mapType(parameter.getOutType()); + Type sharedVarType = typeMapper.getSharedVarType(parameter); if (sharedVarType != null) { + Type localVarType = typeMapper.mapType(parameter.getOutType()); int index = frameMap.getIndex(parameter); mv.visitTypeInsn(NEW, sharedVarType.getInternalName()); mv.visitInsn(DUP); @@ -134,13 +179,30 @@ public class FunctionCodegen { Label methodEnd = new Label(); mv.visitLabel(methodEnd); - // http://youtrack.jetbrains.net/issue/KT-746 - // Fill LocalVariableTable with method parameter names - for (int i = 0; i < paramDescrs.size(); i++) { - ValueParameterDescriptor parameter = paramDescrs.get(i); - Type type = state.getTypeMapper().mapType(parameter.getOutType()); + int k = 0; + + if(expectedThisObject.exists()) { + Type type = typeMapper.mapType(expectedThisObject.getType()); // TODO: specify signature - mv.visitLocalVariable(parameter.getName(), type.getDescriptor(), null, methodBegin, methodEnd, i + add); + mv.visitLocalVariable("this", type.getDescriptor(), null, methodBegin, methodEnd, k++); + } + + if(receiverParameter.exists()) { + Type type = typeMapper.mapType(receiverParameter.getType()); + // TODO: specify signature + mv.visitLocalVariable("this$receiver", type.getDescriptor(), null, methodBegin, methodEnd, k); + k += type.getSize(); + } + + for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + mv.visitLocalVariable(typeParameterDescriptor.getName(), JetTypeMapper.TYPE_TYPEINFO.getDescriptor(), null, methodBegin, methodEnd, k++); + } + + for (ValueParameterDescriptor parameter : paramDescrs) { + Type type = typeMapper.mapType(parameter.getOutType()); + // TODO: specify signature + mv.visitLocalVariable(parameter.getName(), type.getDescriptor(), null, methodBegin, methodEnd, k); + k += type.getSize(); } mv.visitMaxs(0, 0); @@ -210,7 +272,7 @@ public class FunctionCodegen { if (v.generateCode()) { mv.visitCode(); - FrameMap frameMap = owner.prepareFrame(); + FrameMap frameMap = owner.prepareFrame(state.getTypeMapper()); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 5649fe11f01..f65d0b75dce 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -348,9 +348,6 @@ public class JetTypeMapper { final JetType receiverType = !receiverTypeRef.exists() ? null : receiverTypeRef.getType(); final List parameters = f.getValueParameters(); List parameterTypes = new ArrayList(); - if (receiverType != null) { - parameterTypes.add(mapType(receiverType)); - } if(kind == OwnerKind.TRAIT_IMPL) { ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); @@ -362,6 +359,9 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } + if (receiverType != null) { + parameterTypes.add(mapType(receiverType)); + } for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { parameterTypes.add(TYPE_TYPEINFO); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java index 2bcfbc5804d..72d2ae08868 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java @@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; +import org.objectweb.asm.Type; import java.util.List; @@ -17,6 +18,9 @@ import java.util.List; * @author alex.tkachman */ public class SignatureUtil { + private SignatureUtil() { + } + public static String classToSignature(JetClass type, BindingContext bindingContext, JetTypeMapper typeMapper) { StringBuilder sb = new StringBuilder(); genTypeParams(type, sb); @@ -33,7 +37,7 @@ public class SignatureUtil { DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); if(descriptor instanceof ClassDescriptor) { JetType defaultType = ((ClassDescriptor) descriptor).getDefaultType(); - org.objectweb.asm.Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION); + Type type = typeMapper.mapType(defaultType, OwnerKind.IMPLEMENTATION); if(JetTypeMapper.isPrimitive(type)) { type = JetTypeMapper.boxType(type); } diff --git a/stdlib/src/jet/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java new file mode 100644 index 00000000000..a999ce2f298 --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetMethod.java @@ -0,0 +1,27 @@ +package jet.typeinfo; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for method + * + * The fact of receiver presence must be deducted from presence of 'this$receiver' parameter + * + * @author alex.tkachman + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JetMethod { + /** + * @return type projections or empty + */ + JetTypeProjection[] returnTypeProjections() default {}; + + /** + * @return is this type returnTypeNullable + */ + boolean nullableReturnType() default false; +} diff --git a/stdlib/src/jet/typeinfo/JetParameter.java b/stdlib/src/jet/typeinfo/JetParameter.java new file mode 100644 index 00000000000..bae06e264b1 --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetParameter.java @@ -0,0 +1,35 @@ +package jet.typeinfo; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for parameters + * + * @author alex.tkachman + */ +@Target({ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JetParameter { + /** + * @return name of parameter + */ + String name (); + + /** + * @return type projections or empty + */ + JetTypeProjection[] typeProjections() default {}; + + /** + * @return is this type nullable + */ + boolean nullable () default false; + + /** + * @return if this parameter has default value + */ + boolean hasDefaultValue () default false; +} diff --git a/stdlib/src/jet/typeinfo/JetTypeDescriptor.java b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java new file mode 100644 index 00000000000..9d289c97b41 --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java @@ -0,0 +1,20 @@ +package jet.typeinfo; + +/** + * @author alex.tkachman + */ +public @interface JetTypeDescriptor{ + // + // case of type parameter + // + String varName() default ""; + boolean reified () default true; + TypeInfoVariance variance() default TypeInfoVariance.INVARIANT; + int [] upperBounds() default {}; + + // + // case of real type + // + Class javaClass() default Object.class; + JetTypeProjection [] projections() default {}; +} diff --git a/stdlib/src/jet/typeinfo/JetParameterName.java b/stdlib/src/jet/typeinfo/JetTypeParameter.java similarity index 67% rename from stdlib/src/jet/typeinfo/JetParameterName.java rename to stdlib/src/jet/typeinfo/JetTypeParameter.java index 904da5dc449..b57809b98e5 100644 --- a/stdlib/src/jet/typeinfo/JetParameterName.java +++ b/stdlib/src/jet/typeinfo/JetTypeParameter.java @@ -6,10 +6,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * Annotation for parameters + * * @author alex.tkachman */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) -public @interface JetParameterName { - String value (); +public @interface JetTypeParameter { + /** + * @return name of parameter + */ + String name(); } diff --git a/stdlib/src/jet/typeinfo/JetTypeProjection.java b/stdlib/src/jet/typeinfo/JetTypeProjection.java new file mode 100644 index 00000000000..3605c0640e6 --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetTypeProjection.java @@ -0,0 +1,20 @@ +package jet.typeinfo; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author alex.tkachman + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface JetTypeProjection { + /** + * @return variance of the type + */ + TypeInfoVariance variance(); + + /** + * @return index of the class in the per class table of JetTypeDescriptor + */ + int typeDescriptorIndex(); +} diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 75f84bb22f2..fa7abb6afa1 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -60,7 +60,7 @@ public abstract class TypeInfo implements JetObject { // @NotNull @Override public TypeInfoVariance getVariance() { - return TypeInfoVariance.IN_VARIANCE; + return TypeInfoVariance.IN; } }; } @@ -70,7 +70,7 @@ public abstract class TypeInfo implements JetObject { // @NotNull @Override public TypeInfoVariance getVariance() { - return TypeInfoVariance.OUT_VARIANCE; + return TypeInfoVariance.OUT; } }; } @@ -606,11 +606,11 @@ public abstract class TypeInfo implements JetObject { private TypeInfoVariance parseVariance() { if(string[cur] == 'i' && string[cur+1] == 'n' && string[cur+2] == ' ' ) { cur += 3; - return TypeInfoVariance.IN_VARIANCE; + return TypeInfoVariance.IN; } else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+3] == ' ') { cur += 4; - return TypeInfoVariance.OUT_VARIANCE; + return TypeInfoVariance.OUT; } else { return TypeInfoVariance.INVARIANT; diff --git a/stdlib/src/jet/typeinfo/TypeInfoVariance.java b/stdlib/src/jet/typeinfo/TypeInfoVariance.java index 410d45e3c49..647bb6693a9 100644 --- a/stdlib/src/jet/typeinfo/TypeInfoVariance.java +++ b/stdlib/src/jet/typeinfo/TypeInfoVariance.java @@ -5,8 +5,8 @@ package jet.typeinfo; */ public enum TypeInfoVariance { INVARIANT("") , - IN_VARIANCE("in"), - OUT_VARIANCE("out"); + IN("in"), + OUT("out"); private final String label;