diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index 74a523bbe39..8f284c416fc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -81,9 +81,14 @@ public class CallableMethod implements Callable { public void invokeWithDefault(InstructionAdapter v, int mask) { v.iconst(mask); String desc = getSignature().getDescriptor().replace(")", "I)"); - if(getInvokeOpcode() != Opcodes.INVOKESTATIC) - desc = desc.replace("(", "(L" + getOwner() + ";"); - v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc); + if("".equals(getSignature().getName())) { + v.visitMethodInsn(Opcodes.INVOKESPECIAL, getOwner(), "", desc); + } + else { + if(getInvokeOpcode() != Opcodes.INVOKESTATIC) + desc = desc.replace("(", "(L" + getOwner() + ";"); + v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc); + } } public boolean isNeedsThis() { 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 2969bed7be7..a51e784419a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -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); @@ -164,7 +226,7 @@ public class FunctionCodegen { } } - static void generateDefaultIfNeeded(CodegenContext.MethodContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { + static void generateDefaultIfNeeded(CodegenContext.MethodContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, @Nullable FunctionDescriptor functionDescriptor, OwnerKind kind) { DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); if(kind != OwnerKind.TRAIT_IMPL) { @@ -180,15 +242,18 @@ public class FunctionCodegen { } boolean needed = false; - for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { - if(parameterDescriptor.hasDefaultValue()) { - needed = true; - break; + if(functionDescriptor != null) { + for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { + if(parameterDescriptor.hasDefaultValue()) { + needed = true; + break; + } } } if(needed) { - boolean hasReceiver = functionDescriptor.getReceiverParameter().exists(); + ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); + boolean hasReceiver = receiverParameter.exists(); boolean isStatic = kind == OwnerKind.NAMESPACE; if(kind == OwnerKind.TRAIT_IMPL) { @@ -203,46 +268,42 @@ public class FunctionCodegen { state.getTypeMapper().mapType(((ClassDescriptor) contextClass).getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(); String descriptor = jvmSignature.getDescriptor().replace(")","I)"); - if(!isStatic) + boolean isConstructor = "".equals(jvmSignature.getName()); + if(!isStatic && !isConstructor) descriptor = descriptor.replace("(","(L" + ownerInternalName + ";"); - final MethodVisitor mv = v.newMethod(null, flags | ACC_STATIC, jvmSignature.getName() + "$default", descriptor, null, null); + final MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC), isConstructor ? "" : jvmSignature.getName() + "$default", descriptor, null, null); InstructionAdapter iv = new InstructionAdapter(mv); 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); int var = 0; if(!isStatic) { - frameMap.enterTemp(); var++; } + Type receiverType = receiverParameter.exists() ? state.getTypeMapper().mapType(receiverParameter.getType()) : Type.DOUBLE_TYPE; if(hasReceiver) { - frameMap.enterTemp(); - var++; + var += receiverType.getSize(); } List typeParameters = functionDescriptor.getTypeParameters(); for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { - int slot = frameMap.enterTemp(); - codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(slot, JetTypeMapper.TYPE_TYPEINFO)); - var++; + if(typeParameterDescriptor.isReified()) { + codegen.addTypeParameter(typeParameterDescriptor, StackValue.local(var++, JetTypeMapper.TYPE_TYPEINFO)); + } } Type[] argTypes = jvmSignature.getArgumentTypes(); List paramDescrs = functionDescriptor.getValueParameters(); for (int i = 0; i < paramDescrs.size(); i++) { - ValueParameterDescriptor parameter = paramDescrs.get(i); int size = argTypes[i + (hasReceiver ? 1 : 0)].getSize(); var += size; - frameMap.enter(parameter, size); } - frameMap.enterTemp(); - int maskIndex = var; var = 0; @@ -251,7 +312,8 @@ public class FunctionCodegen { } if(hasReceiver) { - mv.visitVarInsn(ALOAD, var++); // todo - Long etc. + iv.load(var, receiverType); + var += receiverType.getSize(); } int extra = hasReceiver ? 1 : 0; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index c3fe305c016..d9a6678e5f2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -269,7 +269,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); - Method method; + Method constructorMethod; CallableMethod callableMethod; if (constructorDescriptor == null) { List parameterTypes = new ArrayList(); @@ -282,17 +282,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); } - method = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.emptyList()); + constructorMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); + callableMethod = new CallableMethod("", constructorMethod, Opcodes.INVOKESPECIAL, Collections.emptyList()); } else { callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind); - method = callableMethod.getSignature(); + constructorMethod = callableMethod.getSignature(); } ObjectOrClosureCodegen closure = context.closure; if(closure != null) { - final List consArgTypes = new LinkedList(Arrays.asList(method.getArgumentTypes())); + final List consArgTypes = new LinkedList(Arrays.asList(constructorMethod.getArgumentTypes())); int insert = 0; if(closure.captureThis) { @@ -319,11 +319,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - method = new Method("", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); + constructorMethod = new Method("", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); } int flags = Opcodes.ACC_PUBLIC; // TODO - final MethodVisitor mv = v.newMethod(myClass, flags, "", method.getDescriptor(), null, null); + final MethodVisitor mv = v.newMethod(myClass, flags, "", constructorMethod.getDescriptor(), null, null); if (!v.generateCode()) return; mv.visitCode(); @@ -470,6 +470,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); + + FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorMethod, constructorDescriptor, OwnerKind.IMPLEMENTATION ); } private void generateTraitMethods(ExpressionCodegen codegen) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 5ad68c7182d..da8f91a181f 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/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java index e813857f0de..1255b108ef2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java @@ -5,6 +5,7 @@ import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -31,11 +32,11 @@ public class BinaryOp implements IntrinsicMethod { if (receiver != null) { receiver.put(expectedType, v); } - codegen.gen(arguments.get(0), expectedType); + codegen.gen(arguments.get(0), shift() ? Type.INT_TYPE : expectedType); } else { codegen.gen(arguments.get(0), expectedType); - codegen.gen(arguments.get(1), expectedType); + codegen.gen(arguments.get(1), shift() ? Type.INT_TYPE : expectedType); } v.visitInsn(expectedType.getOpcode(opcode)); @@ -44,4 +45,8 @@ public class BinaryOp implements IntrinsicMethod { } return StackValue.onStack(expectedType); } + + private boolean shift() { + return opcode == Opcodes.ISHL || opcode == Opcodes.ISHR || opcode == Opcodes.IUSHR; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java index 86850d21051..ac46bd31b60 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/RangeTo.java @@ -18,16 +18,24 @@ import java.util.List; public class RangeTo implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { - JetBinaryExpression expression = (JetBinaryExpression) element; - final Type leftType = codegen.expressionType(expression.getLeft()); - if (JetTypeMapper.isIntPrimitive(leftType)) { - codegen.gen(expression.getLeft(), Type.INT_TYPE); - codegen.gen(expression.getRight(), Type.INT_TYPE); + if(arguments.size()==1) { + receiver.put(Type.INT_TYPE, v); + codegen.gen(arguments.get(0), Type.INT_TYPE); v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); } else { - throw new UnsupportedOperationException("ranges are only supported for int objects"); + JetBinaryExpression expression = (JetBinaryExpression) element; + final Type leftType = codegen.expressionType(expression.getLeft()); + if (JetTypeMapper.isIntPrimitive(leftType)) { + codegen.gen(expression.getLeft(), Type.INT_TYPE); + codegen.gen(expression.getRight(), Type.INT_TYPE); + v.invokestatic("jet/IntRange", "rangeTo", "(II)Ljet/IntRange;"); + return StackValue.onStack(JetTypeMapper.TYPE_INT_RANGE); + } + else { + throw new UnsupportedOperationException("ranges are only supported for int objects"); + } } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeReference.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeReference.java index faf32b925fd..8dc33d8aa50 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeReference.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeReference.java @@ -10,6 +10,9 @@ import java.util.Collections; import java.util.List; /** + * Type reference element. + * Underlying token is {@link org.jetbrains.jet.JetNodeTypes#TYPE_REFERENCE} + * * @author max */ public class JetTypeReference extends JetElement { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 5a14b835dad..5e8557fd62a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -41,11 +41,15 @@ public interface BindingContext { WritableSlice> INDEXED_LVALUE_SET = Slices.createSimpleSlice(); WritableSlice AUTOCAST = Slices.createSimpleSlice(); + + /** A scope where type of expression has been resolved */ WritableSlice RESOLUTION_SCOPE = Slices.createSimpleSlice(); WritableSlice VARIABLE_REASSIGNMENT = Slices.createSimpleSetSlice(); WritableSlice AUTO_CREATED_IT = Slices.createSimpleSetSlice(); WritableSlice VARIABLE_ASSIGNMENT = Slices.createSimpleSlice(); + + /** Has type of current expression has been already resolved */ WritableSlice PROCESSED = Slices.createSimpleSetSlice(); WritableSlice STATEMENT = Slices.createRemovableSetSlice(); WritableSlice DELEGATED = Slices.createRemovableSetSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 654135be994..8896830d305 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -49,11 +49,14 @@ public class TypeResolver { JetTypeElement typeElement = typeReference.getTypeElement(); JetType type = resolveTypeElement(scope, annotations, typeElement, false); trace.record(BindingContext.TYPE, typeReference, type); + return type; } @NotNull - private JetType resolveTypeElement(final JetScope scope, final List annotations, JetTypeElement typeElement, final boolean nullable) { + private JetType resolveTypeElement(final JetScope scope, final List annotations, + JetTypeElement typeElement, final boolean nullable) { + final JetType[] result = new JetType[1]; if (typeElement != null) { typeElement.accept(new JetVisitorVoid() { @@ -70,6 +73,7 @@ public class TypeResolver { resolveTypeProjections(scope, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments()); return; } + if (classifierDescriptor instanceof TypeParameterDescriptor) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) classifierDescriptor; @@ -268,6 +272,8 @@ public class TypeResolver { ClassifierDescriptor classifierDescriptor; if (userType.isAbsoluteInRootNamespace()) { classifierDescriptor = JetModuleUtil.getRootNamespaceType(userType).getMemberScope().getClassifier(referencedName); + trace.record(BindingContext.RESOLUTION_SCOPE, userType.getReferenceExpression(), + JetModuleUtil.getRootNamespaceType(userType).getMemberScope()); } else { JetUserType qualifier = userType.getQualifier(); @@ -278,7 +284,9 @@ public class TypeResolver { return ErrorUtils.getErrorClass(); } classifierDescriptor = scope.getClassifier(referencedName); + trace.record(BindingContext.RESOLUTION_SCOPE, userType.getReferenceExpression(), scope); } + return classifierDescriptor; } diff --git a/compiler/testData/codegen/regressions/kt684.jet b/compiler/testData/codegen/regressions/kt684.jet new file mode 100644 index 00000000000..41048cec7c5 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt684.jet @@ -0,0 +1,29 @@ +fun escapeChar(c : Char) : String? = when (c) { + '\\' => "\\\\" + '\n' => "\\n" + '"' => "\\\"" + else => String.valueOf(c) +} + +fun String.escape(i : Int = 0, result : String = "") : String = + if (i == length) result + else escape(i + 1, result + escapeChar(get(i))) + +fun box() : String { + val s = " System.out?.println(\"fun escapeChar(c : Char) : String? = when (c) {\");\n System.out?.println(\" '\\\\\\\\' => \\\"\\\\\\\\\\\\\\\\\\\"\");\n System.out?.println(\" '\\\\n' => \\\"\\\\\\\\n\\\"\");\n System.out?.println(\" '\\\"' => \\\"\\\\\\\\\\\\\\\"\\\"\");\n System.out?.println(\" else => String.valueOf(c)\");\n System.out?.println(\"}\");\n System.out?.println();\n System.out?.println(\"fun String.escape(i : Int = 0, result : String = \\\"\\\") : String =\");\n System.out?.println(\" if (i == length) result\");\n System.out?.println(\" else escape(i + 1, result + escapeChar(this.get(i)))\");\n System.out?.println();\n System.out?.println(\"fun main(args : Array) {\");\n System.out?.println(\" val s = \\\"\" + s.escape() + \"\\\";\");\n System.out?.println(s);\n}\n"; + System.out?.println("fun escapeChar(c : Char) : String? = when (c) {"); + System.out?.println(" '\\\\' => \"\\\\\\\\\""); + System.out?.println(" '\\n' => \"\\\\n\""); + System.out?.println(" '\"' => \"\\\\\\\"\""); + System.out?.println(" else => String.valueOf(c)"); + System.out?.println("}"); + System.out?.println(); + System.out?.println("fun String.escape(i : Int = 0, result : String = \"\") : String ="); + System.out?.println(" if (i == length) result"); + System.out?.println(" else escape(i + 1, result + escapeChar(this.get(i)))"); + System.out?.println(); + System.out?.println("fun main(args : Array) {"); + System.out?.println(" val s = \"" + s.escape() + "\";"); + System.out?.println(s); + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt752.jet b/compiler/testData/codegen/regressions/kt752.jet new file mode 100644 index 00000000000..20132c9f6a8 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt752.jet @@ -0,0 +1,12 @@ +namespace demo_range + +fun Int?.rangeTo(other : Int?) : IntRange = this.sure().rangeTo(other.sure()) + +fun box() : String { + val x : Int? = 10 + val y : Int? = 12 + + for (i in x..y) + System.out?.println(i.inv()) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt753.jet b/compiler/testData/codegen/regressions/kt753.jet new file mode 100644 index 00000000000..a1b81de8138 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt753.jet @@ -0,0 +1,11 @@ +namespace bitwise_demo + +fun Long?.shl(bits : Int?) : Long = this.sure().shl(bits.sure()) + +fun box() : String { + val x : Long? = 10 + val y : Int? = 12 + + System.out?.println(x.shl(y)) + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java index 9fda35ee5ad..b11121da4e6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PrimitiveTypesTest.java @@ -317,7 +317,7 @@ public class PrimitiveTypesTest extends CodegenTestCase { public void testKt737() throws Exception { loadText("fun box() = if(3.compareTo(2) != 1) \"fail\" else if(5.byt.compareTo(10.lng) >= 0) \"fail\" else \"OK\""); - System.out.println(generateToText()); +// System.out.println(generateToText()); assertEquals("OK", blackBox()); } @@ -337,4 +337,19 @@ public class PrimitiveTypesTest extends CodegenTestCase { // System.out.println(generateToText()); blackBox(); } + + public void testKt752 () { + blackBoxFile("regressions/kt752.jet"); +// System.out.println(generateToText()); + } + + public void testKt753 () { + blackBoxFile("regressions/kt753.jet"); +// System.out.println(generateToText()); + } + + public void testKt684 () { + blackBoxFile("regressions/kt684.jet"); +// System.out.println(generateToText()); + } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 4d57ce51d53..9fb52fa377c 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -79,7 +79,6 @@ class JetSimpleNameReference extends JetPsiReference { private Object[] collectLookupElements(BindingContext bindingContext, JetScope scope) { List result = Lists.newArrayList(); for (final DeclarationDescriptor descriptor : scope.getAllDescriptors()) { - PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal()); LookupElementBuilder element = LookupElementBuilder.create(descriptor.getName()); String typeText = ""; String tailText = ""; @@ -108,9 +107,12 @@ class JetSimpleNameReference extends JetPsiReference { typeText = DescriptorRenderer.TEXT.render(descriptor); } element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText); + + PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal()); if (declaration != null) { element = element.setIcon(declaration.getIcon(Iconable.ICON_FLAG_OPEN | Iconable.ICON_FLAG_VISIBILITY)); } + result.add(element); } return result.toArray(); diff --git a/idea/testData/completion/basic/ExtendClassName.kt b/idea/testData/completion/basic/ExtendClassName.kt new file mode 100644 index 00000000000..47daf28eff9 --- /dev/null +++ b/idea/testData/completion/basic/ExtendClassName.kt @@ -0,0 +1,13 @@ +open class MySecondClass() { +} + +open class MyFirstClass { + +} + +class A() : My { + public fun test() { + } +} + +// EXIST: MySecondClass, MyFirstClass \ No newline at end of file diff --git a/idea/testData/completion/basic/ExtendQualifiedClassName.kt b/idea/testData/completion/basic/ExtendQualifiedClassName.kt new file mode 100644 index 00000000000..da13ff4b8c0 --- /dev/null +++ b/idea/testData/completion/basic/ExtendQualifiedClassName.kt @@ -0,0 +1,11 @@ +namespace Test.SubTest.AnotherTest + +open class TestClass { +} + +class A() : Test.SubTest.AnotherTest.Te { + public fun test() { + } +} + +// EXIST: TestClass diff --git a/idea/testData/completion/basic/VariableClassName.kt b/idea/testData/completion/basic/VariableClassName.kt new file mode 100644 index 00000000000..0296a23af4c --- /dev/null +++ b/idea/testData/completion/basic/VariableClassName.kt @@ -0,0 +1,10 @@ +open class MyClass() { +} + +class A() : My { + public fun test() { + val a : MyC + } +} + +// EXIST: MyClass \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java new file mode 100644 index 00000000000..14bc6d16912 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java @@ -0,0 +1,59 @@ +package org.jetbrains.jet.completion; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.JetTestCaseBuilder; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.io.File; + +/** + * @author Nikolay.Krasko + */ +public class JetBasicCompletionTest extends JetCompletionTestBase { + private final String myPath; + private final String myName; + + public JetBasicCompletionTest(@NotNull String path, @NotNull String name) { + myPath = path; + myName = name; + + // Set name explicitly because otherwise there will be "TestCase.fName cannot be null" + setName("testCompletionExecute"); + } + + public void testCompletionExecute() { + doTest(); + } + + @Override + protected String getTestDataPath() { + return new File(PluginTestCaseBase.getTestDataPathBase(), myPath).getPath() + + File.separator; + } + + @NotNull + @Override + public String getName() { + return "test" + myName; + } + + @NotNull + public static TestSuite suite() { + TestSuite suite = new TestSuite(); + + JetTestCaseBuilder.appendTestsInDirectory( + PluginTestCaseBase.getTestDataPathBase(), "/completion/basic/", false, + JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() { + + @NotNull + @Override + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + return new JetBasicCompletionTest(dataPath, name); + } + }, suite); + + return suite; + } +} diff --git a/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java index f214d6e0043..1df0d5ef2cf 100644 --- a/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/KeywordsCompletionTest.java @@ -22,10 +22,10 @@ public class KeywordsCompletionTest extends JetCompletionTestBase { myName = name; // Set name explicitly because otherwise there will be "TestCase.fName cannot be null" - setName("testComletionExecute"); + setName("testCompletionExecute"); } - public void testComletionExecute() { + public void testCompletionExecute() { doTest(); } 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;