diff --git a/.gitignore b/.gitignore index 1af2e47cf73..852cf881b6e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ out .idea/codeStyleSettings.xml .idea/workspace.xml tmp +*TestMy.java diff --git a/.idea/modules.xml b/.idea/modules.xml index 463eb8bb67f..9c559c5bba1 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -12,6 +12,7 @@ + diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index 59d472f16d7..83d535a52a1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -126,9 +126,7 @@ public abstract class ClassBodyCodegen { } mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - - mv.visitEnd(); + FunctionCodegen.endVisit(v, "static initializer", myClass); } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index feced45f382..38e58aa2846 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -147,8 +147,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { mv.visitLabel(ret); mv.visitInsn(ARETURN); - mv.visitMaxs(0,0); - mv.visitEnd(); + FunctionCodegen.endVisit(mv, "$getInstance", fun); } } @@ -205,8 +204,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { iv.areturn(JetTypeMapper.TYPE_OBJECT); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(mv, "bridge", fun); } } @@ -286,8 +284,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { iv.visitInsn(RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "constructor", fun); } return constructor; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CompilationException.java b/compiler/backend/src/org/jetbrains/jet/codegen/CompilationException.java new file mode 100644 index 00000000000..84f336f74a5 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CompilationException.java @@ -0,0 +1,20 @@ +package org.jetbrains.jet.codegen; + +import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.psi.JetElement; + +/** +* @author alex.tkachman +*/ +public class CompilationException extends RuntimeException { + private PsiElement element; + + CompilationException(String message, Throwable cause, PsiElement element) { + super(message, cause); + this.element = element; + } + + public PsiElement getElement() { + return element; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 39101c75e48..8dafa6b2690 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -130,7 +130,15 @@ public class ExpressionCodegen extends JetVisitor { public StackValue genQualified(StackValue receiver, JetElement selector) { markLineNumber(selector); - return selector.accept(this, receiver); + try { + return selector.accept(this, receiver); + } + catch(CompilationException e) { + throw e; + } + catch (Throwable error) { + throw new CompilationException(error.getMessage(), error, selector); + } } public StackValue gen(JetElement expr) { @@ -204,7 +212,7 @@ public class ExpressionCodegen extends JetVisitor { JetExpression elseExpression = expression.getElse(); if (thenExpression == null && elseExpression == null) { - throw new CompilationException(); + throw new CompilationException("Both brunches of if/else are null", null, expression); } if (isEmptyExpression(thenExpression)) { @@ -225,6 +233,9 @@ public class ExpressionCodegen extends JetVisitor { condition.condJump(elseLabel, true, v); // == 0, i.e. false Label end = continueLabel == null ? new Label() : continueLabel; + + if(continueLabel != null) + asmType = Type.VOID_TYPE; gen(thenExpression, asmType); @@ -1126,7 +1137,7 @@ public class ExpressionCodegen extends JetVisitor { ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee); if(resolvedCall == null) { - throw new CompilationException("Cannot resolve: " + callee.getText()); + throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression); } receiver = StackValue.receiver(resolvedCall, receiver, this, null); @@ -1403,7 +1414,7 @@ public class ExpressionCodegen extends JetVisitor { return mask; } - private int pushMethodArguments(JetCallElement expression, List valueParameterTypes) { + public int pushMethodArguments(JetCallElement expression, List valueParameterTypes) { ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); if(resolvedCall != null) { return pushMethodArguments(resolvedCall, valueParameterTypes); @@ -2074,7 +2085,7 @@ public class ExpressionCodegen extends JetVisitor { ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee); if(resolvedCall == null) { assert callee != null; - throw new CompilationException("Cannot resolve: " + callee.getText()); + throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression); } FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor(); @@ -2098,7 +2109,7 @@ public class ExpressionCodegen extends JetVisitor { } else { if (args.size() != 1) { - throw new CompilationException("primitive array constructor requires one argument"); + throw new CompilationException("primitive array constructor requires one argument", null, expression); } } @@ -2784,15 +2795,6 @@ If finally block is present, its last expression is the value of try expression. v.athrow(); } - private static class CompilationException extends RuntimeException { - private CompilationException() { - } - - private CompilationException(String message) { - super(message); - } - } - @Override public String toString() { return context.getContextDescriptor().toString(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index befdaf21a7e..c8c9f3dee79 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -110,6 +110,7 @@ public class FunctionCodegen { if(receiverParameter.getType().isNullable()) { av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } + av.visit(StdlibNames.JET_VALUE_PARAMETER_RECEIVER_FIELD, true); av.visitEnd(); } for (final TypeParameterDescriptor typeParameterDescriptor : typeParameters) { @@ -223,7 +224,7 @@ public class FunctionCodegen { k += type.getSize(); } - mv.visitMaxs(0, 0); + endVisit(mv, null, fun); mv.visitEnd(); generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind); @@ -233,6 +234,16 @@ public class FunctionCodegen { generateDefaultIfNeeded(context, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind); } + public static void endVisit(MethodVisitor mv, String description, PsiElement method) { + try { + mv.visitMaxs(0, 0); + } + catch (Throwable t) { + throw new CompilationException("wrong code generated" + (description != null ? " for " + description : "") + t.getClass().getName() + " " + t.getMessage(), t, method); + } + mv.visitEnd(); + } + static void generateBridgeIfNeeded(CodegenContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) { Set overriddenFunctions = functionDescriptor.getOverriddenDescriptors(); if(kind != OwnerKind.TRAIT_IMPL) { @@ -390,7 +401,7 @@ public class FunctionCodegen { iv.areturn(jvmSignature.getReturnType()); - mv.visitMaxs(0, 0); + endVisit(mv, "default method", state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor)); mv.visitEnd(); } } @@ -426,7 +437,7 @@ public class FunctionCodegen { if(jvmSignature.getReturnType() == Type.VOID_TYPE) iv.aconst(null); iv.areturn(overriden.getReturnType()); - mv.visitMaxs(0, 0); + endVisit(mv, "bridge method", state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor)); mv.visitEnd(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 77c65e1c4d4..852b12ac22e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -198,8 +198,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor()); iv.areturn(method.getReturnType()); - mv.visitMaxs(0,0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "accessor", null); } } else if(entry.getValue() instanceof PropertyDescriptor) { @@ -222,8 +221,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor()); iv.areturn(method.getReturnType()); - mv.visitMaxs(0,0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "accessor", null); } method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getAsmMethod(); @@ -248,8 +246,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.invokespecial(typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION), originalMethod.getName(), originalMethod.getDescriptor()); iv.areturn(method.getReturnType()); - mv.visitMaxs(0,0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "accessor", null); } } else { @@ -465,8 +462,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { outer.visitVarInsn(Opcodes.ALOAD, 0); outer.visitFieldInsn(Opcodes.GETFIELD, classname, "this$0", outerType.getDescriptor()); outer.visitInsn(Opcodes.ARETURN); - outer.visitMaxs(0, 0); - outer.visitEnd(); + FunctionCodegen.endVisit(outer, "getOuterObject", myClass); } if (CodegenUtil.requireTypeInfoConstructorArg(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { @@ -518,8 +514,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateTraitMethods(codegen); mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(mv, "constructor", myClass); FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorMethod, constructorDescriptor, OwnerKind.IMPLEMENTATION); } @@ -572,8 +567,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.checkcast(function.getReturnType()); } iv.areturn(function.getReturnType()); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "trait method", bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, fun)); } FunctionCodegen.generateBridgeIfNeeded(context, state, v, function, fun, kind); @@ -708,8 +702,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(mv, "constructor", null); } } @@ -821,8 +814,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); iv.areturn(JetTypeMapper.TYPE_TYPEINFO); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "getTypeInfo", myClass); } mv = v.newMethod(myClass, Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V", null, null); @@ -834,8 +826,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(1, JetTypeMapper.TYPE_OBJECT); iv.putfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(iv, "$setTypeInfo", myClass); } } } @@ -853,8 +844,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { String owner = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(); v.getstatic(owner, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); v.areturn(JetTypeMapper.TYPE_TYPEINFO); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(v, "getTypeInfo", myClass); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 0272124ec9b..ef2cef70364 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -66,7 +66,6 @@ public class JetTypeMapper { private final HashMap knowTypeNames = new HashMap(); private final HashMap knowTypes = new HashMap(); - public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public static final Type TYPE_ITERATOR = Type.getObjectType("jet/Iterator"); public static final Type TYPE_INT_RANGE = Type.getObjectType("jet/IntRange"); public static final Type TYPE_SHARED_VAR = Type.getObjectType("jet/runtime/SharedVar$Object"); @@ -86,6 +85,8 @@ public class JetTypeMapper { public static final Type TYPE_LONG_ITERATOR = Type.getObjectType("jet/LongIterator"); public static final Type TYPE_FLOAT_ITERATOR = Type.getObjectType("jet/FloatIterator"); public static final Type TYPE_DOUBLE_ITERATOR = Type.getObjectType("jet/DoubleIterator"); + public static final Type TYPE_FUNCTION0 = Type.getObjectType("jet/Function0"); + public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public JetStandardLibrary getStandardLibrary() { return standardLibrary; @@ -557,7 +558,10 @@ public class JetTypeMapper { } } - // "extends Object" seems to be not optional according to ClassFileFormat-Java5.pdf + // "extends Object" is optional according to ClassFileFormat-Java5.pdf + // but javac complaints to signature: + // Ljava/lang/Object; + // TODO: avoid writing java/lang/Object if interface list is not empty } signatureVisitor.writeClassBoundEnd(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 5e8b92a7849..78a768791e1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -62,8 +62,11 @@ public class NamespaceCodegen { else if (declaration instanceof JetNamedFunction) { try { functionCodegen.gen((JetNamedFunction) declaration); - } catch (Exception e) { - throw new RuntimeException("Failed to generate function " + declaration.getName(), e); + } catch (CompilationException e) { + throw e; + } + catch (Exception e) { + throw new CompilationException("Failed to generate function " + declaration.getName(), e, declaration); } } else if (declaration instanceof JetClassOrObject) { @@ -107,7 +110,7 @@ public class NamespaceCodegen { } mv.visitInsn(RETURN); - mv.visitMaxs(0, 0); + FunctionCodegen.endVisit(mv, "static initializer for namespace", namespace); mv.visitEnd(); } } @@ -134,8 +137,7 @@ public class NamespaceCodegen { v.visitFieldInsn(PUTSTATIC, jvmClassName, fieldName, "Ljet/typeinfo/TypeInfo;"); v.visitLabel(end); v.visitInsn(ARETURN); - v.visitMaxs(0, 0); - v.visitEnd(); + FunctionCodegen.endVisit(v, "type info method", namespace); } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index dc05e02b32d..2267922aeb7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -154,8 +154,7 @@ public class PropertyCodegen { type.getDescriptor()); } iv.areturn(type); - mv.visitMaxs(0, 0); - mv.visitEnd(); + FunctionCodegen.endVisit(mv, "getter", origin); } } @@ -207,7 +206,7 @@ public class PropertyCodegen { } iv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); + FunctionCodegen.endVisit(mv, "setter", origin); mv.visitEnd(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java index 79374780086..893d9ce47b3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java @@ -20,6 +20,7 @@ import java.util.*; /** * @author yole + * @author alex.tkachman */ public class IntrinsicMethods { private static final IntrinsicMethod UNARY_MINUS = new UnaryMinus(); @@ -89,6 +90,7 @@ public class IntrinsicMethods { declareOverload(myStdLib.getLibraryScope().getFunctions("plus"), 1, new StringPlus()); declareOverload(myStdLib.getLibraryScope().getFunctions("Array"), 1, new NewArray()); declareOverload(myStdLib.getLibraryScope().getFunctions("sure"), 0, new Sure()); + declareOverload(myStdLib.getLibraryScope().getFunctions("synchronized"), 1, new StupidSync()); declareIntrinsicFunction("ByteIterator", "next", 0, ITERATOR_NEXT); declareIntrinsicFunction("ShortIterator", "next", 0, ITERATOR_NEXT); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/StupidSync.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/StupidSync.java new file mode 100644 index 00000000000..1e83272f26e --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/StupidSync.java @@ -0,0 +1,26 @@ +package org.jetbrains.jet.codegen.intrinsics; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.lang.psi.JetCallExpression; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Label; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; + +import java.util.Arrays; +import java.util.List; + +public class StupidSync implements IntrinsicMethod { + @Override + public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, @Nullable PsiElement element, @Nullable List arguments, StackValue receiver) { + receiver.put(receiver.type, v); + codegen.pushMethodArguments((JetCallExpression)element, Arrays.asList(JetTypeMapper.TYPE_FUNCTION0)); + v.invokestatic("jet/runtime/Intrinsics", "stupidSync", "(Ljava/lang/Object;Ljet/Function0;)Ljava/lang/Object;"); + StackValue.onStack(JetTypeMapper.TYPE_OBJECT).put(expectedType, v); + return StackValue.onStack(expectedType); + } +} 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 88689127062..6948e7ac5fe 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 @@ -9,6 +9,7 @@ import com.intellij.psi.*; import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import jet.typeinfo.TypeInfoVariance; +import org.eclipse.jdt.internal.core.JavaModelManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -56,9 +57,38 @@ public class JavaDescriptorResolver { return visitor.visitDeclarationDescriptor(this, data); } }; + + private enum TypeParameterDescriptorOrigin { + JAVA, + KOTLIN, + } + + private static class TypeParameterDescriptorInitialization { + private final TypeParameterDescriptorOrigin origin; + private final TypeParameterDescriptor descriptor; + @Nullable + private final List upperBoundsForKotlin; + @Nullable + private final List lowerBoundsForKotlin; + + private TypeParameterDescriptorInitialization(TypeParameterDescriptor descriptor) { + this.origin = TypeParameterDescriptorOrigin.JAVA; + this.descriptor = descriptor; + this.upperBoundsForKotlin = null; + this.lowerBoundsForKotlin = null; + } + + private TypeParameterDescriptorInitialization(TypeParameterDescriptor descriptor, + List upperBoundsForKotlin, List lowerBoundsForKotlin) { + this.origin = TypeParameterDescriptorOrigin.KOTLIN; + this.descriptor = descriptor; + this.upperBoundsForKotlin = upperBoundsForKotlin; + this.lowerBoundsForKotlin = lowerBoundsForKotlin; + } + } protected final Map classDescriptorCache = Maps.newHashMap(); - protected final Map typeParameterDescriptorCache = Maps.newHashMap(); + protected final Map typeParameterDescriptorCache = Maps.newHashMap(); protected final Map methodDescriptorCache = Maps.newHashMap(); protected final Map fieldDescriptorCache = Maps.newHashMap(); protected final Map namespaceDescriptorCache = Maps.newHashMap(); @@ -145,11 +175,8 @@ public class JavaDescriptorResolver { classDescriptorCache.put(psiClass.getQualifiedName(), classDescriptor); classDescriptor.setUnsubstitutedMemberScope(new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false)); - // TODO: initialize - if (psiClass.getModifierList().findAnnotation(StdlibNames.JET_CLASS.getFqName()) == null) { - // UGLY HACK (Andrey Breslav is not sure what did he mean) - initializeTypeParameters(psiClass); - } + // UGLY HACK (Andrey Breslav is not sure what did he mean) + initializeTypeParameters(psiClass); supertypes.addAll(getSupertypes(psiClass)); if (psiClass.isInterface()) { @@ -188,7 +215,11 @@ public class JavaDescriptorResolver { classDescriptor, Collections.emptyList(), // TODO false); - constructorDescriptor.initialize(typeParameters, resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()), Modality.FINAL, + ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(constructorDescriptor, constructor.getParameterList().getParameters()); + if (valueParameterDescriptors.receiverType != null) { + throw new IllegalStateException(); + } + constructorDescriptor.initialize(typeParameters, valueParameterDescriptors.descriptors, Modality.FINAL, resolveVisibilityFromPsiModifiers(constructor)); constructorDescriptor.setReturnType(classDescriptor.getDefaultType()); classDescriptor.addConstructor(constructorDescriptor); @@ -208,7 +239,7 @@ public class JavaDescriptorResolver { if (attributeValue != null) { String typeParametersString = (String) attributeValue.getValue(); if (typeParametersString != null) { - return resolveClassTypeParametersFromJetSignature(typeParametersString, classDescriptor); + return resolveClassTypeParametersFromJetSignature(typeParametersString, psiClass, classDescriptor); } } } @@ -216,49 +247,107 @@ public class JavaDescriptorResolver { return makeUninitializedTypeParameters(classDescriptor, psiClass.getTypeParameters()); } + @NotNull + private PsiTypeParameter getPsiTypeParameterByName(PsiTypeParameterListOwner clazz, String name) { + for (PsiTypeParameter typeParameter : clazz.getTypeParameters()) { + if (typeParameter.getName().equals(name)) { + return typeParameter; + } + } + throw new IllegalStateException("PsiTypeParameter '" + name + "' is not found"); + } + + + // cache + protected ClassDescriptor javaLangObject; + + @NotNull + private ClassDescriptor getJavaLangObject() { + if (javaLangObject == null) { + javaLangObject = resolveClass("java.lang.Object"); + } + return javaLangObject; + } + + private boolean isJavaLangObject(JetType type) { + return type.getConstructor().getDeclarationDescriptor() == getJavaLangObject(); + } + + + private abstract class JetSignatureTypeParameterVisitor extends JetSignatureExceptionsAdapter { + + private final DeclarationDescriptor containingDeclaration; + private final PsiTypeParameterListOwner psiOwner; + private final String name; + private final TypeInfoVariance variance; + + protected JetSignatureTypeParameterVisitor(DeclarationDescriptor containingDeclaration, PsiTypeParameterListOwner psiOwner, + String name, TypeInfoVariance variance) + { + this.containingDeclaration = containingDeclaration; + this.psiOwner = psiOwner; + this.name = name; + this.variance = variance; + } + + int index = 0; + + List upperBounds = new ArrayList(); + List lowerBounds = new ArrayList(); + + @Override + public JetSignatureVisitor visitClassBound() { + return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { + @Override + protected void done(@NotNull JetType jetType) { + if (isJavaLangObject(jetType)) { + return; + } + upperBounds.add(jetType); + } + }; + } + + @Override + public JetSignatureVisitor visitInterfaceBound() { + return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { + @Override + protected void done(@NotNull JetType jetType) { + upperBounds.add(jetType); + } + }; + } + + @Override + public void visitFormalTypeParameterEnd() { + TypeParameterDescriptor typeParameter = TypeParameterDescriptor.createForFurtherModification( + containingDeclaration, + Collections.emptyList(), // TODO: wrong + true, // TODO: wrong + JetSignatureUtils.translateVariance(variance), + name, + ++index); + PsiTypeParameter psiTypeParameter = getPsiTypeParameterByName(psiOwner, name); + typeParameterDescriptorCache.put(psiTypeParameter, new TypeParameterDescriptorInitialization(typeParameter, upperBounds, lowerBounds)); + done(typeParameter); + } + + protected abstract void done(TypeParameterDescriptor typeParameterDescriptor); + } + /** * @see #resolveMethodTypeParametersFromJetSignature(String, FunctionDescriptor) */ - private List resolveClassTypeParametersFromJetSignature(String jetSignature, final JavaClassDescriptor classDescriptor) { + private List resolveClassTypeParametersFromJetSignature(String jetSignature, final PsiClass clazz, final JavaClassDescriptor classDescriptor) { final List r = new ArrayList(); new JetSignatureReader(jetSignature).accept(new JetSignatureExceptionsAdapter() { @Override public JetSignatureVisitor visitFormalTypeParameter(final String name, final TypeInfoVariance variance) { - return new JetSignatureExceptionsAdapter() { - int index = 0; - + return new JetSignatureTypeParameterVisitor(classDescriptor, clazz, name, variance) { @Override - public JetSignatureVisitor visitClassBound() { - return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { - @Override - protected void done(@NotNull JetType jetType) { - // TODO - } - }; + protected void done(TypeParameterDescriptor typeParameterDescriptor) { + r.add(typeParameterDescriptor); } - - @Override - public JetSignatureVisitor visitInterfaceBound() { - return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { - @Override - protected void done(@NotNull JetType jetType) { - // TODO - } - }; - } - - @Override - public void visitFormalTypeParameterEnd() { - TypeParameterDescriptor typeParameter = TypeParameterDescriptor.createForFurtherModification( - classDescriptor, - Collections.emptyList(), // TODO: wrong - true, // TODO: wrong - JetSignatureUtils.translateVariance(variance), - name, - ++index); - r.add(typeParameter); - } - }; } @@ -308,34 +397,49 @@ public class JavaDescriptorResolver { psiTypeParameter.getName(), psiTypeParameter.getIndex() ); - typeParameterDescriptorCache.put(psiTypeParameter, typeParameterDescriptor); + typeParameterDescriptorCache.put(psiTypeParameter, new TypeParameterDescriptorInitialization(typeParameterDescriptor)); return typeParameterDescriptor; } - private void initializeTypeParameter(PsiTypeParameter typeParameter, TypeParameterDescriptor typeParameterDescriptor) { - PsiClassType[] referencedTypes = typeParameter.getExtendsList().getReferencedTypes(); - if (referencedTypes.length == 0){ - typeParameterDescriptor.addUpperBound(JetStandardClasses.getNullableAnyType()); - } - else if (referencedTypes.length == 1) { - typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedTypes[0])); - } - else { - for (PsiClassType referencedType : referencedTypes) { - typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedType)); + private void initializeTypeParameter(PsiTypeParameter typeParameter, TypeParameterDescriptorInitialization typeParameterDescriptorInitialization) { + TypeParameterDescriptor typeParameterDescriptor = typeParameterDescriptorInitialization.descriptor; + if (typeParameterDescriptorInitialization.origin == TypeParameterDescriptorOrigin.KOTLIN) { + List upperBounds = typeParameterDescriptorInitialization.upperBoundsForKotlin; + if (upperBounds.size() == 0){ + typeParameterDescriptor.addUpperBound(JetStandardClasses.getNullableAnyType()); + } else { + for (JetType upperBound : typeParameterDescriptorInitialization.upperBoundsForKotlin) { + typeParameterDescriptor.addUpperBound(upperBound); + } + } + + // TODO: lower bounds + } else { + PsiClassType[] referencedTypes = typeParameter.getExtendsList().getReferencedTypes(); + if (referencedTypes.length == 0){ + typeParameterDescriptor.addUpperBound(JetStandardClasses.getNullableAnyType()); + } + else if (referencedTypes.length == 1) { + typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedTypes[0])); + } + else { + for (PsiClassType referencedType : referencedTypes) { + typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedType)); + } } } + typeParameterDescriptor.setInitialized(); } private void initializeTypeParameters(PsiTypeParameterListOwner typeParameterListOwner) { for (PsiTypeParameter psiTypeParameter : typeParameterListOwner.getTypeParameters()) { - initializeTypeParameter(psiTypeParameter, resolveTypeParameter(psiTypeParameter)); + initializeTypeParameter(psiTypeParameter, resolveTypeParameterInitialization(psiTypeParameter)); } } @NotNull - private TypeParameterDescriptor resolveTypeParameter(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter psiTypeParameter) { - TypeParameterDescriptor typeParameterDescriptor = typeParameterDescriptorCache.get(psiTypeParameter); + private TypeParameterDescriptorInitialization resolveTypeParameter(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter psiTypeParameter) { + TypeParameterDescriptorInitialization typeParameterDescriptor = typeParameterDescriptorCache.get(psiTypeParameter); assert typeParameterDescriptor != null : psiTypeParameter.getText(); return typeParameterDescriptor; } @@ -423,21 +527,71 @@ public class JavaDescriptorResolver { semanticServices.getTrace().record(BindingContext.NAMESPACE, psiClass, namespaceDescriptor); return namespaceDescriptor; } + + private static class ValueParameterDescriptors { + private final JetType receiverType; + private final List descriptors; - public List resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) { - List result = new ArrayList(); - for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { - PsiParameter parameter = parameters[i]; - ValueParameterDescriptor valueParameterDescriptor = resolveParameterDescriptor(containingDeclaration, i, parameter); - if (valueParameterDescriptor != null) { - result.add(valueParameterDescriptor); - } + private ValueParameterDescriptors(@Nullable JetType receiverType, List descriptors) { + this.receiverType = receiverType; + this.descriptors = descriptors; } - return result; } - @Nullable - private ValueParameterDescriptor resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { + public ValueParameterDescriptors resolveParameterDescriptors(DeclarationDescriptor containingDeclaration, PsiParameter[] parameters) { + List result = new ArrayList(); + JetType receiverType = null; + for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { + PsiParameter parameter = parameters[i]; + JvmMethodParameterMeaning meaning = resolveParameterDescriptor(containingDeclaration, i, parameter); + if (meaning.kind == JvmMethodParameterKind.TYPE_INFO) { + // TODO + } else if (meaning.kind == JvmMethodParameterKind.REGULAR) { + result.add(meaning.valueParameterDescriptor); + } else if (meaning.kind == JvmMethodParameterKind.RECEIVER) { + if (receiverType != null) { + throw new IllegalStateException("more then one receiver"); + } + receiverType = meaning.receiverType; + } + } + return new ValueParameterDescriptors(receiverType, result); + } + + private enum JvmMethodParameterKind { + REGULAR, + RECEIVER, + TYPE_INFO, + } + + private static class JvmMethodParameterMeaning { + private final JvmMethodParameterKind kind; + private final JetType receiverType; + private final ValueParameterDescriptor valueParameterDescriptor; + private final Object typeInfo; + + private JvmMethodParameterMeaning(JvmMethodParameterKind kind, JetType receiverType, ValueParameterDescriptor valueParameterDescriptor, Object typeInfo) { + this.kind = kind; + this.receiverType = receiverType; + this.valueParameterDescriptor = valueParameterDescriptor; + this.typeInfo = typeInfo; + } + + public static JvmMethodParameterMeaning receiver(@NotNull JetType receiverType) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.RECEIVER, receiverType, null, null); + } + + public static JvmMethodParameterMeaning regular(@NotNull ValueParameterDescriptor valueParameterDescriptor) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.REGULAR, null, valueParameterDescriptor, null); + } + + public static JvmMethodParameterMeaning typeInfo(@NotNull Object typeInfo) { + return new JvmMethodParameterMeaning(JvmMethodParameterKind.TYPE_INFO, null, null, typeInfo); + } + } + + @NotNull + private JvmMethodParameterMeaning resolveParameterDescriptor(DeclarationDescriptor containingDeclaration, int i, PsiParameter parameter) { PsiType psiType = parameter.getType(); JetType varargElementType; @@ -453,13 +607,11 @@ public class JavaDescriptorResolver { boolean nullable = true; String typeFromAnnotation = null; + boolean receiver = false; + // TODO: must be very slow, make it lazy? String name = parameter.getName() != null ? parameter.getName() : "p" + i; for (PsiAnnotation annotation : parameter.getModifierList().getAnnotations()) { - // TODO: softcode annotation name - - PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); - attributes.toString(); if (annotation.getQualifiedName().equals(StdlibNames.JET_VALUE_PARAMETER.getFqName())) { PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD); @@ -480,8 +632,16 @@ public class JavaDescriptorResolver { if (signatureExpression != null) { typeFromAnnotation = (String) signatureExpression.getValue(); } + + + PsiLiteralExpression receiverExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_RECEIVER_FIELD); + if (receiverExpression != null) { + receiver = true; + } + + } else if (annotation.getQualifiedName().equals(StdlibNames.JET_TYPE_PARAMETER.getFqName())) { - return null; + return JvmMethodParameterMeaning.typeInfo(new Object()); } } @@ -491,16 +651,20 @@ public class JavaDescriptorResolver { } else { outType = semanticServices.getTypeTransformer().transformToType(psiType); } - return new ValueParameterDescriptorImpl( - containingDeclaration, - i, - Collections.emptyList(), // TODO - name, - null, // TODO : review - changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, - false, - varargElementType - ); + if (receiver) { + return JvmMethodParameterMeaning.receiver(outType); + } else { + return JvmMethodParameterMeaning.regular(new ValueParameterDescriptorImpl( + containingDeclaration, + i, + Collections.emptyList(), // TODO + name, + null, // TODO : review + changeNullable ? TypeUtils.makeNullableAsSpecified(outType, nullable) : outType, + false, + varargElementType + )); + } } public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) { @@ -592,12 +756,13 @@ public class JavaDescriptorResolver { ); methodDescriptorCache.put(method, functionDescriptorImpl); List typeParameters = resolveMethodTypeParameters(method, functionDescriptorImpl); + ValueParameterDescriptors valueParameterDescriptors = resolveParameterDescriptors(functionDescriptorImpl, parameters); functionDescriptorImpl.initialize( - null, + valueParameterDescriptors.receiverType, DescriptorUtils.getExpectedThisObjectIfNeeded(classDescriptor), typeParameters, - semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters), - semanticServices.getDescriptorResolver().makeReturnType(returnType, method), + valueParameterDescriptors.descriptors, + makeReturnType(returnType, method), Modality.convertFromFlags(method.hasModifierProperty(PsiModifier.ABSTRACT), !method.hasModifierProperty(PsiModifier.FINAL)), resolveVisibilityFromPsiModifiers(method) ); @@ -616,7 +781,9 @@ public class JavaDescriptorResolver { if (attributeValue != null) { String typeParametersString = (String) attributeValue.getValue(); if (typeParametersString != null) { - return resolveMethodTypeParametersFromJetSignature(typeParametersString, functionDescriptorImpl); + List r = resolveMethodTypeParametersFromJetSignature(typeParametersString, method, functionDescriptorImpl); + initializeTypeParameters(method); + return r; } } } @@ -628,49 +795,21 @@ public class JavaDescriptorResolver { } /** - * @see #resolveClassTypeParametersFromJetSignature(String, JavaClassDescriptor) + * @see #resolveClassTypeParametersFromJetSignature(String, com.intellij.psi.PsiClass, JavaClassDescriptor) */ - private List resolveMethodTypeParametersFromJetSignature(String jetSignature, final FunctionDescriptor functionDescriptor) { + private List resolveMethodTypeParametersFromJetSignature(String jetSignature, final PsiMethod method, final FunctionDescriptor functionDescriptor) { final List r = new ArrayList(); new JetSignatureReader(jetSignature).acceptFormalTypeParametersOnly(new JetSignatureExceptionsAdapter() { @Override public JetSignatureVisitor visitFormalTypeParameter(final String name, final TypeInfoVariance variance) { - - return new JetSignatureExceptionsAdapter() { - int index = 0; - + + return new JetSignatureTypeParameterVisitor(functionDescriptor, method, name, variance) { @Override - public JetSignatureVisitor visitClassBound() { - return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { - @Override - protected void done(@NotNull JetType jetType) { - // TODO - } - }; - } - - @Override - public JetSignatureVisitor visitInterfaceBound() { - return new JetTypeJetSignatureReader(JavaDescriptorResolver.this, semanticServices.getJetSemanticServices().getStandardLibrary()) { - @Override - protected void done(@NotNull JetType jetType) { - // TODO - } - }; - } - - @Override - public void visitFormalTypeParameterEnd() { - TypeParameterDescriptor typeParameter = TypeParameterDescriptor.createForFurtherModification( - functionDescriptor, - Collections.emptyList(), // TODO: wrong - true, // TODO: wrong - JetSignatureUtils.translateVariance(variance), - name, - ++index); - r.add(typeParameter); + protected void done(TypeParameterDescriptor typeParameterDescriptor) { + r.add(typeParameterDescriptor); } }; + } }); return r; @@ -719,7 +858,8 @@ public class JavaDescriptorResolver { (modifierListOwner.hasModifierProperty(PsiModifier.PROTECTED) ? Visibility.PROTECTED : Visibility.INTERNAL)); } - public TypeParameterDescriptor resolveTypeParameter(PsiTypeParameter typeParameter) { + @NotNull + private TypeParameterDescriptorInitialization resolveTypeParameterInitialization(PsiTypeParameter typeParameter) { PsiTypeParameterListOwner owner = typeParameter.getOwner(); if (owner instanceof PsiClass) { PsiClass psiClass = (PsiClass) owner; @@ -744,4 +884,8 @@ public class JavaDescriptorResolver { } throw new IllegalStateException("Unknown parent type: " + owner); } + + public TypeParameterDescriptor resolveTypeParameter(PsiTypeParameter typeParameter) { + return resolveTypeParameterInitialization(typeParameter).descriptor; + } } 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 dd071b38631..285ffe54b3c 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_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_VALUE_PARAMETER_RECEIVER_FIELD = "receiver"; public static final JvmClassName JET_TYPE_PARAMETER = new JvmClassName("jet.typeinfo.JetTypeParameter"); diff --git a/compiler/frontend/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index 580d1dd1a2b..c54b0d2c49e 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -34,6 +34,8 @@ namespace io { fun readLine() : String? } +fun Any.synchronized(block : fun() : R) : R + fun Any?.identityEquals(other : Any?) : Boolean // = this === other // Can't write a body due to a bootstrapping problem (see JET-74) @@ -103,6 +105,38 @@ trait Iterable { fun iterator() : Iterator } +trait ByteIterable : Iterable { + override fun iterator() : ByteIterator +} + +trait ShortIterable : Iterable { + override fun iterator() : ShortIterator +} + +trait IntIterable : Iterable { + override fun iterator() : IntIterator +} + +trait LongIterable : Iterable { + override fun iterator() : LongIterator +} + +trait FloatIterable : Iterable { + override fun iterator() : FloatIterator +} + +trait DoubleIterable : Iterable { + override fun iterator() : DoubleIterator +} + +trait BooleanIterable : Iterable { + override fun iterator() : BooleanIterator +} + +trait CharIterable : Iterable { + override fun iterator() : CharIterator +} + fun Array(val size : Int) : Array class Array(val size : Int, init : fun(Int) : T) { @@ -230,7 +264,7 @@ trait Range> { fun contains(item : T) : Boolean } -class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, Iterable { +class IntRange(val start : Int, size : Int, reversed : Boolean = false) : Range, IntIterable { fun iterator () : Iterator fun contains (elem: Int) : Boolean diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java index 1edf93c8743..bbd1e6899b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java @@ -28,6 +28,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement int index) { TypeParameterDescriptor typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index); typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound()); + typeParameterDescriptor.setInitialized(); return typeParameterDescriptor; } @@ -52,6 +53,8 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement private final boolean reified; + private boolean initialized = false; + private TypeParameterDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @NotNull List annotations, @@ -74,25 +77,61 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement upperBounds); } + public void setInitialized() { + if (initialized) { + throw new IllegalStateException(); + } + initialized = true; + } + + private void checkInitialized() { + if (!initialized) { + throw new IllegalStateException(); + } + } + + private void checkUninitialized() { + if (initialized) { + throw new IllegalStateException(); + } + } + public boolean isReified() { + checkInitialized(); return reified; } public Variance getVariance() { + checkInitialized(); return variance; } public void addUpperBound(@NotNull JetType bound) { + checkUninitialized(); + doAddUpperBound(bound); + } + + private void doAddUpperBound(JetType bound) { upperBounds.add(bound); // TODO : Duplicates? } + public void addDefaultUpperBound() { + checkUninitialized(); + + if (upperBounds.isEmpty()) { + doAddUpperBound(JetStandardClasses.getDefaultBound()); + } + } + @NotNull public Set getUpperBounds() { + checkInitialized(); return upperBounds; } @NotNull public JetType getUpperBoundsAsType() { + checkInitialized(); if (upperBoundsAsType == null) { assert upperBounds != null : "Upper bound list is null in " + getName(); assert upperBounds.size() > 0 : "Upper bound list is empty in " + getName(); @@ -106,11 +145,13 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @NotNull public Set getLowerBounds() { + //checkInitialized(); return Collections.singleton(JetStandardClasses.getNothingType()); } @NotNull public JetType getLowerBoundsAsType() { + checkInitialized(); return JetStandardClasses.getNothingType(); } @@ -118,6 +159,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @NotNull @Override public TypeConstructor getTypeConstructor() { + //checkInitialized(); return typeConstructor; } @@ -135,12 +177,14 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { + checkInitialized(); return visitor.visitTypeParameterDescriptor(this, data); } @NotNull @Override public JetType getDefaultType() { + //checkInitialized(); if (defaultType == null) { defaultType = new JetTypeImpl( Collections.emptyList(), @@ -159,6 +203,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @Override public JetType getClassObjectType() { + checkInitialized(); if (classObjectUpperBounds.isEmpty()) return null; if (classObjectBoundsAsType == null) { @@ -176,15 +221,19 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement } public void addClassObjectBound(@NotNull JetType bound) { + checkUninitialized(); classObjectUpperBounds.add(bound); // TODO : Duplicates? } public int getIndex() { + checkInitialized(); return index; } @NotNull public TypeParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) { - return new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), reified, variance, getName(), index); + TypeParameterDescriptor copy = new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), reified, variance, getName(), index); + copy.initialized = this.initialized; + return copy; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index c5df77d3682..740ff3ed692 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -381,9 +381,9 @@ public class DescriptorResolver { } for (TypeParameterDescriptor parameter : parameters) { - if (parameter.getUpperBounds().isEmpty()) { - parameter.addUpperBound(JetStandardClasses.getDefaultBound()); - } + parameter.addDefaultUpperBound(); + + parameter.setInitialized(); if (JetStandardClasses.isNothing(parameter.getUpperBoundsAsType())) { PsiElement nameIdentifier = typeParameters.get(parameter.getIndex()).getNameIdentifier(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 2401d6328e4..11d84cc5851 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -19,6 +19,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; import org.jetbrains.jet.lang.types.expressions.OperatorConventions; +import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; import java.util.*; @@ -348,7 +349,7 @@ public class CallResolver { if (callElement instanceof JetBinaryExpression) { JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement; JetSimpleNameExpression operationReference = binaryExpression.getOperationReference(); - String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol(operationReference.getReferencedNameElementType()); + String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol((JetToken) operationReference.getReferencedNameElementType()); JetExpression right = binaryExpression.getRight(); if (right != null) { trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, right.getText())); @@ -510,15 +511,6 @@ public class CallResolver { } else { tracing.typeInferenceFailed(temporaryTrace, solution.getStatus()); -// // Substitute DONT_CARE types to make further type checking as tolerant as possible -// D candidateWithDontCares = (D) candidate.substitute(TypeSubstitutor.makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE)); -// if (candidateWithDontCares == null) { -// candidateWithDontCares = (D) candidate.substitute(TypeSubstitutor.makeConstantSubstitutor(candidate.getTypeParameters(), Variance.INVARIANT, DONT_CARE)); -// } -// if (!ErrorUtils.isErrorType(candidateWithDontCares.getReturnType())) { -// // Returning an error type provokes overload resolution ambiguities that mask errors -// candidateCall.setResultingDescriptor(candidateWithDontCares); -// } candidateCall.setStatus(OTHER_ERROR.combine(checkAllValueArguments(scope, tracing, task, candidateCall))); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java index 3da752a9950..270e5804ff3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java @@ -259,7 +259,7 @@ public class ConstraintSystemWithPriorities implements ConstraintSystem { assert constraintQueue.isEmpty() || unsolvedUnknowns.isEmpty() : constraintQueue + " " + unsolvedUnknowns; - for (TypeValue unknown : unsolvedUnknowns) { + for (TypeValue unknown : Sets.newLinkedHashSet(unsolvedUnknowns)) { if (!computeValueFor(unknown)) { listener.error("Not enough data to compute value for ", unknown); solution.registerError("Not enough data to compute value for " + unknown + ". Please, specify type arguments explicitly"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java index b31f101c402..7101dfda584 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java @@ -44,6 +44,7 @@ public class DescriptorSubstitutor { descriptor.getVariance(), descriptor.getName(), descriptor.getIndex()); + substituted.setInitialized(); mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjection(substituted.getDefaultType())); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java index 570d75fb38b..2aea399ef4e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/OperatorConventions.java @@ -1,10 +1,11 @@ package org.jetbrains.jet.lang.types.expressions; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; /** @@ -12,6 +13,10 @@ import org.jetbrains.jet.lexer.JetTokens; */ public class OperatorConventions { + public static final String EQUALS = "equals"; + public static final String COMPARE_TO = "compareTo"; + public static final String CONTAINS = "contains"; + private OperatorConventions() {} public static final ImmutableSet NUMBER_CONVERSIONS = ImmutableSet.of( @@ -23,7 +28,7 @@ public class OperatorConventions { "int" ); - public static final ImmutableMap UNARY_OPERATION_NAMES = ImmutableMap.builder() + public static final ImmutableBiMap UNARY_OPERATION_NAMES = ImmutableBiMap.builder() .put(JetTokens.PLUSPLUS, "inc") .put(JetTokens.MINUSMINUS, "dec") .put(JetTokens.PLUS, "plus") @@ -31,7 +36,7 @@ public class OperatorConventions { .put(JetTokens.EXCL, "not") .build(); - public static final ImmutableMap BINARY_OPERATION_NAMES = ImmutableMap.builder() + public static final ImmutableBiMap BINARY_OPERATION_NAMES = ImmutableBiMap.builder() .put(JetTokens.MUL, "times") .put(JetTokens.PLUS, "plus") .put(JetTokens.MINUS, "minus") @@ -41,11 +46,22 @@ public class OperatorConventions { .put(JetTokens.RANGE, "rangeTo") .build(); - public static final ImmutableSet COMPARISON_OPERATIONS = ImmutableSet.of(JetTokens.LT, JetTokens.GT, JetTokens.LTEQ, JetTokens.GTEQ); - public static final ImmutableSet EQUALS_OPERATIONS = ImmutableSet.of(JetTokens.EQEQ, JetTokens.EXCLEQ); + public static final ImmutableSet NOT_OVERLOADABLE = + ImmutableSet.of(JetTokens.ANDAND, JetTokens.OROR, JetTokens.ELVIS); + + public static final ImmutableSet INCREMENT_OPERATIONS = + ImmutableSet.of(JetTokens.PLUSPLUS, JetTokens.MINUSMINUS); - public static final ImmutableSet IN_OPERATIONS = ImmutableSet.of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN); - public static final ImmutableMap ASSIGNMENT_OPERATIONS = ImmutableMap.builder() + public static final ImmutableSet COMPARISON_OPERATIONS = + ImmutableSet.of(JetTokens.LT, JetTokens.GT, JetTokens.LTEQ, JetTokens.GTEQ); + + public static final ImmutableSet EQUALS_OPERATIONS = + ImmutableSet.of(JetTokens.EQEQ, JetTokens.EXCLEQ); + + public static final ImmutableSet IN_OPERATIONS = + ImmutableSet.of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN); + + public static final ImmutableBiMap ASSIGNMENT_OPERATIONS = ImmutableBiMap.builder() .put(JetTokens.MULTEQ, "timesAssign") .put(JetTokens.DIVEQ, "divAssign") .put(JetTokens.PERCEQ, "modAssign") @@ -53,7 +69,7 @@ public class OperatorConventions { .put(JetTokens.MINUSEQ, "minusAssign") .build(); - public static final ImmutableMap ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableMap.builder() + public static final ImmutableMap ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableMap.builder() .put(JetTokens.MULTEQ, JetTokens.MUL) .put(JetTokens.DIVEQ, JetTokens.DIV) .put(JetTokens.PERCEQ, JetTokens.PERC) @@ -62,17 +78,16 @@ public class OperatorConventions { .build(); @Nullable - public static String getNameForOperationSymbol(@NotNull IElementType token) { + public static String getNameForOperationSymbol(@NotNull JetToken token) { String name = UNARY_OPERATION_NAMES.get(token); if (name != null) return name; name = BINARY_OPERATION_NAMES.get(token); if (name != null) return name; name = ASSIGNMENT_OPERATIONS.get(token); if (name != null) return name; - if (COMPARISON_OPERATIONS.contains(token)) return "compareTo"; - if (EQUALS_OPERATIONS.contains(token)) return "equals"; - if (IN_OPERATIONS.contains(token)) return "contains"; + if (COMPARISON_OPERATIONS.contains(token)) return COMPARE_TO; + if (EQUALS_OPERATIONS.contains(token)) return EQUALS; + if (IN_OPERATIONS.contains(token)) return CONTAINS; return null; - } - + } } diff --git a/compiler/testData/codegen/controlStructures/ifInWhile.jet b/compiler/testData/codegen/controlStructures/ifInWhile.jet new file mode 100644 index 00000000000..834c71f2b6f --- /dev/null +++ b/compiler/testData/codegen/controlStructures/ifInWhile.jet @@ -0,0 +1,14 @@ +import java.lang.Runtime + +fun box() : String { + val processors = Runtime.getRuntime().sure().availableProcessors() + var threadNum = 1 + while(threadNum <= 1024) { + System.out?.println(threadNum) + if(threadNum < 2 * processors) + threadNum += 1 + else + threadNum *= 2 + } + return "OK" +} diff --git a/compiler/testData/codegen/controlStructures/sync.jet b/compiler/testData/codegen/controlStructures/sync.jet new file mode 100644 index 00000000000..408db40ca36 --- /dev/null +++ b/compiler/testData/codegen/controlStructures/sync.jet @@ -0,0 +1,33 @@ +import java.util.concurrent.* +import java.util.concurrent.atomic.* + +fun thread(block: fun():Unit ) { + val thread = object: Thread() { + override fun run() { + block() + } + } + thread.start() +} + +fun box() : String { + val ref = AtomicInteger() + val cdl = CountDownLatch(11) + for(i in 0..10) { + thread { + var current = 0 + do { + current = ref.synchronized { + val v = ref.get() + 1 + if(v < 100) + ref.set(v+1) + v + } + } + while(current < 100) + cdl.countDown() + } + } + cdl.await() + return if(ref.get() == 100) "OK" else ref.get().toString() +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt511.jet b/compiler/testData/codegen/regressions/kt511.jet new file mode 100644 index 00000000000..a9bc915346c --- /dev/null +++ b/compiler/testData/codegen/regressions/kt511.jet @@ -0,0 +1,16 @@ +namespace one_extends_base + +open class Base(name : T?) { + var myName : T? + { + $myName = name + } +} +open class One(name : T?, second : K?) : Base(name) { + var mySecond : K? + { + $mySecond = second + } +} + +fun box() = if(One("ola", 0).myName == "ola") "OK" else "fail" diff --git a/compiler/testData/codegen/regressions/kt772.jet b/compiler/testData/codegen/regressions/kt772.jet new file mode 100644 index 00000000000..6cad8d6ae03 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt772.jet @@ -0,0 +1,25 @@ +namespace demo2 + +fun print(o : Any?) {} + +fun test(i : Int) { + var monthString : String? = "" + when (i) { + 1 => { + print(1) + print(2) + print(3) + print(4) + print(5) + } + else => { + monthString = "Invalid month" + } + } + print(monthString) +} + +fun box() : String { + for (i in 1..12) test(i) + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt779.jet b/compiler/testData/codegen/regressions/kt779.jet new file mode 100644 index 00000000000..12aa290eb67 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt779.jet @@ -0,0 +1,3 @@ +val Array.length : Int get() = this.size + +fun box() = if(Array(10, {1}).length == 10) "OK" else "fail" \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt860.jet b/compiler/testData/diagnostics/tests/regressions/kt860.jet new file mode 100644 index 00000000000..d8acf4fad50 --- /dev/null +++ b/compiler/testData/diagnostics/tests/regressions/kt860.jet @@ -0,0 +1,14 @@ +// KT-860 ConcurrentModificationException in frontend +// +JDK + +namespace std.util + +import java.util.* + +fun > Iterator.to(container: U) : U { + while(hasNext) + container.add(next()) + return container +} + +inline fun Iterator.toArrayList() = to(ArrayList()) diff --git a/compiler/testData/readClass/class/ClassParamUpperClassBound.kt b/compiler/testData/readClass/class/ClassParamUpperClassBound.kt new file mode 100644 index 00000000000..4867fac53bc --- /dev/null +++ b/compiler/testData/readClass/class/ClassParamUpperClassBound.kt @@ -0,0 +1,3 @@ +namespace test + +class Clock diff --git a/compiler/testData/readClass/class/ClassParamUpperClassInterfaceBound.kt b/compiler/testData/readClass/class/ClassParamUpperClassInterfaceBound.kt new file mode 100644 index 00000000000..992a24af91b --- /dev/null +++ b/compiler/testData/readClass/class/ClassParamUpperClassInterfaceBound.kt @@ -0,0 +1,3 @@ +namespace test + +class Clock where A : java.lang.Number, A : java.lang.CharSequence diff --git a/compiler/testData/readClass/class/ClassParamUpperInterfaceBound.kt b/compiler/testData/readClass/class/ClassParamUpperInterfaceBound.kt new file mode 100644 index 00000000000..8f05d69017f --- /dev/null +++ b/compiler/testData/readClass/class/ClassParamUpperInterfaceBound.kt @@ -0,0 +1,3 @@ +namespace test + +class Clock diff --git a/compiler/testData/readClass/class/ClassParamUpperInterfaceClassBound.kt b/compiler/testData/readClass/class/ClassParamUpperInterfaceClassBound.kt new file mode 100644 index 00000000000..8e8170d48c5 --- /dev/null +++ b/compiler/testData/readClass/class/ClassParamUpperInterfaceClassBound.kt @@ -0,0 +1,3 @@ +namespace test + +class Clock where A : java.lang.CharSequence, A : java.lang.Number diff --git a/compiler/testData/readClass/class/Trait.kt b/compiler/testData/readClass/class/Trait.kt new file mode 100644 index 00000000000..b984afa34b0 --- /dev/null +++ b/compiler/testData/readClass/class/Trait.kt @@ -0,0 +1,3 @@ +namespace test + +trait Trtrtr diff --git a/compiler/testData/readClass/fun/ExtFun.kt b/compiler/testData/readClass/fun/ExtFun.kt new file mode 100644 index 00000000000..f894ea8a631 --- /dev/null +++ b/compiler/testData/readClass/fun/ExtFun.kt @@ -0,0 +1,3 @@ +namespace test + +fun Int.shuffle() = 1 diff --git a/compiler/testData/readClass/fun/FunParamUpperClassBound.kt b/compiler/testData/readClass/fun/FunParamUpperClassBound.kt new file mode 100644 index 00000000000..3a4c68fed8f --- /dev/null +++ b/compiler/testData/readClass/fun/FunParamUpperClassBound.kt @@ -0,0 +1,3 @@ +namespace test + +fun uno() = 1 diff --git a/compiler/testData/readClass/fun/FunParamUpperClassInterfaceBound.kt b/compiler/testData/readClass/fun/FunParamUpperClassInterfaceBound.kt new file mode 100644 index 00000000000..678d5a2967a --- /dev/null +++ b/compiler/testData/readClass/fun/FunParamUpperClassInterfaceBound.kt @@ -0,0 +1,3 @@ +namespace test + +fun tres() where A : java.lang.Number, A : java.lang.CharSequence = 1 diff --git a/compiler/testData/readClass/fun/FunParamUpperInterfaceBound.kt b/compiler/testData/readClass/fun/FunParamUpperInterfaceBound.kt new file mode 100644 index 00000000000..00a6e0432cb --- /dev/null +++ b/compiler/testData/readClass/fun/FunParamUpperInterfaceBound.kt @@ -0,0 +1,3 @@ +namespace test + +fun dos() = 1 diff --git a/compiler/testData/readClass/fun/FunParamUpperInterfaceClassBound.kt b/compiler/testData/readClass/fun/FunParamUpperInterfaceClassBound.kt new file mode 100644 index 00000000000..6effa87aba9 --- /dev/null +++ b/compiler/testData/readClass/fun/FunParamUpperInterfaceClassBound.kt @@ -0,0 +1,3 @@ +namespace test + +fun cuatro() where A : java.lang.CharSequence, A : java.lang.Number = 1 diff --git a/compiler/tests/org/jetbrains/jet/CompileJavaAgainstKotlinTest.java b/compiler/tests/org/jetbrains/jet/CompileJavaAgainstKotlinTest.java index 3121cfc8315..8bb9e576bc6 100644 --- a/compiler/tests/org/jetbrains/jet/CompileJavaAgainstKotlinTest.java +++ b/compiler/tests/org/jetbrains/jet/CompileJavaAgainstKotlinTest.java @@ -1,13 +1,10 @@ package org.jetbrains.jet; -import com.intellij.lang.LanguageASTFactory; -import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.PsiFileFactoryImpl; -import com.intellij.psi.impl.source.tree.JavaASTFactory; import com.intellij.testFramework.LightVirtualFile; import com.intellij.testFramework.UsefulTestCase; import junit.framework.Test; @@ -70,8 +67,6 @@ public class CompileJavaAgainstKotlinTest extends UsefulTestCase { protected void runTest() throws Throwable { jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdk(myTestRootDisposable); - LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); - String text = FileUtil.loadFile(ktFile); diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 83e7f8d13c4..04458738032 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -1,14 +1,11 @@ package org.jetbrains.jet; -import com.intellij.lang.LanguageASTFactory; -import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.PsiFileFactoryImpl; -import com.intellij.psi.impl.source.tree.JavaASTFactory; import com.intellij.testFramework.LightVirtualFile; import com.intellij.testFramework.UsefulTestCase; import junit.framework.Test; @@ -18,15 +15,7 @@ import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.lang.JetSemanticServices; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorImpl; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -34,8 +23,8 @@ import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeConstructor; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.plugin.JetLanguage; @@ -44,6 +33,7 @@ import org.junit.Assert; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -92,9 +82,6 @@ public class ReadClassDataTest extends UsefulTestCase { public void runTest() throws Exception { jetCoreEnvironment = JetTestUtils.createEnvironmentWithMockJdk(myTestRootDisposable); - LanguageASTFactory.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, new JavaASTFactory()); - - String text = FileUtil.loadFile(testFile); LightVirtualFile virtualFile = new LightVirtualFile(testFile.getName(), JetLanguage.INSTANCE, text); @@ -159,7 +146,8 @@ public class ReadClassDataTest extends UsefulTestCase { private String serializeContent(ClassDescriptor klass) { StringBuilder sb = new StringBuilder(); - sb.append("class "); + serialize(klass.getKind(), sb); + sb.append(" "); serialize(klass, sb); @@ -174,9 +162,6 @@ public class ReadClassDataTest extends UsefulTestCase { sb.append(" {\n"); - if (false) { - // TODO: for some reason I don't understand scope of ClassDescriptor came from source is empty - List typeArguments = new ArrayList(); for (TypeParameterDescriptor param : klass.getTypeConstructor().getParameters()) { typeArguments.add(new TypeProjection(Variance.INVARIANT, param.getDefaultType())); @@ -184,15 +169,37 @@ public class ReadClassDataTest extends UsefulTestCase { JetScope memberScope = klass.getMemberScope(typeArguments); for (DeclarationDescriptor member : memberScope.getAllDescriptors()) { + // TODO + if (member.getName().equals("equals") || member.getName().equals("hashCode") + || member.getName().equals("wait") || member.getName().equals("notify") || member.getName().equals("notifyAll") + || member.getName().equals("toString") || member.getName().equals("getClass") + || member.getName().equals("clone") || member.getName().equals("finalize") + || member.getName().equals("getTypeInfo") || member.getName().equals("$setTypeInfo") || member.getName().equals("$typeInfo") + ) + { + continue; + } + sb.append(" "); serialize(member, sb); sb.append("\n"); } - } - sb.append("}\n"); return sb.toString(); } + + private void serialize(ClassKind kind, StringBuilder sb) { + switch (kind) { + case CLASS: + sb.append("class"); + break; + case TRAIT: + sb.append("trait"); + break; + default: + throw new IllegalStateException(); + } + } private void compareFunctions(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { @@ -220,6 +227,12 @@ public class ReadClassDataTest extends UsefulTestCase { serializeCommaSeparated(fun.getTypeParameters(), sb); sb.append(">"); } + + if (fun.getReceiverParameter().exists()) { + serialize(fun.getReceiverParameter(), sb); + sb.append("."); + } + sb.append(fun.getName()); sb.append("("); serializeCommaSeparated(fun.getValueParameters(), sb); @@ -227,6 +240,21 @@ public class ReadClassDataTest extends UsefulTestCase { serialize(fun.getReturnType(), sb); } + private void serialize(ExtensionReceiver extensionReceiver, StringBuilder sb) { + serialize(extensionReceiver.getType(), sb); + } + + private void serialize(PropertyDescriptor prop, StringBuilder sb) { + if (prop.isVar()) { + sb.append("var "); + } else { + sb.append("val "); + } + sb.append(prop.getName()); + sb.append(": "); + serialize(prop.getOutType(), sb); + } + private void serialize(ValueParameterDescriptor valueParameter, StringBuilder sb) { sb.append(valueParameter.getName()); sb.append(": "); @@ -274,16 +302,20 @@ public class ReadClassDataTest extends UsefulTestCase { } private void serializeCommaSeparated(List list, StringBuilder sb) { + serializeSeparated(list, sb, ", "); + } + + private void serializeSeparated(List list, StringBuilder sb, String sep) { boolean first = true; for (Object o : list) { if (!first) { - sb.append(", "); + sb.append(sep); } serialize(o, sb); first = false; } } - + private Method getMethodToSerialize(Object o) { // TODO: cache for (Method method : ReadClassDataTest.class.getDeclaredMethods()) { @@ -311,6 +343,10 @@ public class ReadClassDataTest extends UsefulTestCase { Method method = getMethodToSerialize(o); invoke(method, this, o, sb); } + + private void serialize(String s, StringBuilder sb) { + sb.append(s); + } private void serialize(ModuleDescriptor module, StringBuilder sb) { // nop @@ -331,11 +367,20 @@ public class ReadClassDataTest extends UsefulTestCase { sb.append("."); sb.append(ns.getName()); } - + private void serialize(TypeParameterDescriptor param, StringBuilder sb) { serialize(param.getVariance(), sb); sb.append(param.getName()); - // TODO: serialize bounds + if (!param.getUpperBounds().isEmpty()) { + sb.append(" : "); + List list = new ArrayList(); + for (JetType upper : param.getUpperBounds()) { + list.add(serialize(upper)); + } + Collections.sort(list); + serializeSeparated(list, sb, " & "); // TODO: use where + } + // TODO: lower bounds } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 5de65ac38f6..f14c34e279d 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -12,6 +12,11 @@ public class ArrayGenTest extends CodegenTestCase { // System.out.println(generateToText()); } + public void testKt779 () throws Exception { + blackBoxFile("regressions/kt779.jet"); +// System.out.println(generateToText()); + } + public void testCreateMultiInt () throws Exception { loadText("fun foo() = Array> (5, { Array(it, {239}) })"); Method foo = generateFunction(); diff --git a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index b6f0f1b3ad5..2869aa145b4 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -231,8 +231,25 @@ public class ControlStructuresTest extends CodegenTestCase { // System.out.println(generateToText()); } + public void testKt772() throws Exception { + blackBoxFile("regressions/kt772.jet"); +// System.out.println(generateToText()); + } + public void testQuicksort() throws Exception { blackBoxFile("controlStructures/quicksort.jet"); +// System.out.println(generateToText()); + } + + public void testSynchronized() throws Exception { + createEnvironmentWithFullJdk(); + blackBoxFile("controlStructures/sync.jet"); +// System.out.println(generateToText()); + } + + public void testIfInWhile() throws Exception { + createEnvironmentWithFullJdk(); + blackBoxFile("controlStructures/ifInWhile.jet"); // System.out.println(generateToText()); } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index b2396c96af6..3949cf9b8c6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -138,6 +138,11 @@ public class TypeInfoTest extends CodegenTestCase { // System.out.println(generateToText()); } + public void testKt511() throws Exception { + blackBoxFile("regressions/kt511.jet"); +// System.out.println(generateToText()); + } + public void testInner() throws Exception { blackBoxFile("typeInfo/inner.jet"); System.out.println(generateToText()); diff --git a/examples/src/benchmarks/LockPerf.kt b/examples/src/benchmarks/LockPerf.kt index c7a61eda5ed..2937c59dfd1 100644 --- a/examples/src/benchmarks/LockPerf.kt +++ b/examples/src/benchmarks/LockPerf.kt @@ -1,20 +1,13 @@ namespace lockperformance +import std.io.* +import std.util.* +import std.concurrent.* + import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; -fun thread(f: fun ()) { - val thread = Thread( - object: Runnable { - override fun run() { - f() - } - } - ) - thread.start() -} - fun Int.latch(op: fun CountDownLatch.() : T) : T { val cdl = CountDownLatch(this) val res = cdl.op() @@ -22,41 +15,37 @@ fun Int.latch(op: fun CountDownLatch.() : T) : T { return res } -fun Int.times(action: fun Int.()) { - for(i in 0..this-1) - action() -} - fun main(args: Array) { val processors = Runtime.getRuntime().sure().availableProcessors() var threadNum = 1 while(threadNum <= 1024) { val counter = AtomicInteger() - val start = System.currentTimeMillis() - threadNum.latch{ - val lock = ReentrantLock() - threadNum.times { - thread { - while(true) { - lock.lock() - try { - if (counter.get() == 100000000) { - countDown(); - break; - } else { - counter.incrementAndGet(); + val duration = measureTimeMillis { + threadNum.latch{ + val lock = ReentrantLock() + for(i in 0..threadNum-1) { + thread { + while(true) { + lock.lock() + try { + if (counter.get() == 100000000) { + countDown(); + break; + } else { + counter.incrementAndGet(); + } + } + finally { + lock.unlock() } - } - finally { - lock.unlock() } } } } } - System.out?.println(threadNum.toString() + " " + (System.currentTimeMillis() - start)); + println(threadNum.toString() + " " + duration) if(threadNum < 2 * processors) threadNum = threadNum + 1 diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index 21dea6ed517..766868d3fc8 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -16,10 +16,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.util.Chunk; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.codegen.ClassBuilderFactory; -import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.CompilationErrorHandler; -import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.JetFile; @@ -102,7 +99,12 @@ public class JetCompiler implements TranslatingCompiler { generationState.compileCorrectNamespaces(bindingContext, namespaces, new CompilationErrorHandler() { @Override public void reportException(Throwable exception, String fileUrl) { - compileContext.addMessage(CompilerMessageCategory.WARNING, exception.getClass().getCanonicalName() + ": " + exception.getMessage(), fileUrl, 0, 0); + if(exception instanceof CompilationException) { + report((CompilationException) exception, compileContext); + } + else { + compileContext.addMessage(CompilerMessageCategory.ERROR, exception.getClass().getCanonicalName() + ": " + exception.getMessage(), fileUrl, 0, 0); + } } }); /////////// @@ -175,6 +177,29 @@ public class JetCompiler implements TranslatingCompiler { } } + private void report(CompilationException diagnostic, CompileContext compileContext) { + PsiFile psiFile = diagnostic.getElement().getContainingFile(); + TextRange textRange = diagnostic.getElement().getTextRange(); + Document document = psiFile.getViewProvider().getDocument(); + int line; + int col; + if (document != null) { + line = document.getLineNumber(textRange.getStartOffset()); + col = textRange.getStartOffset() - document.getLineStartOffset(line) + 1; + } + else { + line = -1; + col = -1; + } + VirtualFile virtualFile = psiFile.getVirtualFile(); + if (virtualFile == null) { + compileContext.addMessage(ERROR, "[Internal Error] No virtual file for PsiFile. Diagnostic: " + diagnostic.getMessage(), "", -1, -1); + } + else { + compileContext.addMessage(ERROR, diagnostic.getMessage(), virtualFile.getUrl(), line + 1, col); + } + } + // private static class ModuleCompileState { // private final GenerationState state; // private final CompileContext compileContext; diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java index ec99fa7d3df..b858df279df 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.plugin.compiler; import com.google.common.collect.Sets; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; @@ -41,7 +40,7 @@ public final class WholeProjectAnalyzerFacade { final Set namespaces = Sets.newLinkedHashSet(); final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); - if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { + if (rootManager != null /* && !ApplicationManager.getApplication().isUnitTestMode() */) { VirtualFile[] contentRoots = rootManager.getContentRoots(); CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { @@ -57,7 +56,6 @@ public final class WholeProjectAnalyzerFacade { } } }); - } namespaces.add(rootFile.getRootNamespace()); diff --git a/idea/testData/quickfix/autoImports/afterKotlinImport.kt b/idea/testData/quickfix/autoImports/afterKotlinImport.kt new file mode 100644 index 00000000000..e6c19003945 --- /dev/null +++ b/idea/testData/quickfix/autoImports/afterKotlinImport.kt @@ -0,0 +1,7 @@ +// "Import Class" "true" + +import TestData.TestSample + +fun test() { + val a = TestSample +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/beforeKotlinImport.Data.Sample.kt b/idea/testData/quickfix/autoImports/beforeKotlinImport.Data.Sample.kt new file mode 100644 index 00000000000..24ab2e94d15 --- /dev/null +++ b/idea/testData/quickfix/autoImports/beforeKotlinImport.Data.Sample.kt @@ -0,0 +1,3 @@ +namespace TestData + +class TestSample() {} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/beforeKotlinImport.Main.kt b/idea/testData/quickfix/autoImports/beforeKotlinImport.Main.kt new file mode 100644 index 00000000000..9136601298a --- /dev/null +++ b/idea/testData/quickfix/autoImports/beforeKotlinImport.Main.kt @@ -0,0 +1,5 @@ +// "Import Class" "true" + +fun test() { + val a = TestSample +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java new file mode 100644 index 00000000000..9a2714ca055 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java @@ -0,0 +1,226 @@ +package org.jetbrains.jet.plugin.quickfix; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.util.Pair; +import com.intellij.rt.execution.junit.FileComparisonFailure; +import com.intellij.util.ui.UIUtil; +import junit.framework.Test; +import junit.framework.TestSuite; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.JetTestCaseBuilder; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.*; + +/** + * @author Nikolay Krasko + */ +public class JetPsiCheckerMultifileTest extends DaemonAnalyzerTestCase { + + public final static String MAIN_SUBSTRING = ".Main"; + public final static String DATA_SUBSTRING = ".Data"; + + private final String dataPath; + private final String name; + + public JetPsiCheckerMultifileTest(String dataPath, String name) { + this.dataPath = dataPath; + this.name = name; + + setName("testRun"); + } + + protected static boolean shouldBeAvailableAfterExecution() { + return false; + } + + public void testRun() throws Exception { + configureByFiles(null, getFileNames(getTestFiles()).toArray(new String[1])); + doTest(); + } + + public void doTest() { + CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() { + @Override + public void run() { + try { + final Pair pair = LightQuickFixTestCase.parseActionHint(getFile(), loadFile(getFile().getName())); + final String text = pair.getFirst(); + + final boolean actionShouldBeAvailable = pair.getSecond(); + + doAction(text, actionShouldBeAvailable, getTestDataPath()); + } + catch (FileComparisonFailure e){ + throw e; + } + catch (Throwable e) { + e.printStackTrace(); + fail(getTestName(true)); + } + } + }, "", ""); + } + + @SuppressWarnings({"HardCodedStringLiteral"}) + public void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath) + throws Exception { + IntentionAction action = LightQuickFixTestCase.findActionWithText(getAvailableActions(), text); + if (action == null) { + if (actionShouldBeAvailable) { + List actions = getAvailableActions(); + List texts = new ArrayList(); + for (IntentionAction intentionAction : actions) { + texts.add(intentionAction.getText()); + } + Collection infos = doHighlighting(); + fail("Action with text '" + text + "' is not available in test " + testFullPath + "\n" + + "Available actions (" + texts.size() + "): " + texts + "\n" + + actions + "\n" + + "Infos:" + infos); + } + } + else { + if (!actionShouldBeAvailable) { + fail("Action '" + text + "' is available (but must not) in test " + testFullPath); + } + + ShowIntentionActionsHandler.chooseActionAndInvoke(getFile(), getEditor(), action, action.getText()); + + UIUtil.dispatchAllInvocationEvents(); + + if (!shouldBeAvailableAfterExecution()) { + final IntentionAction afterAction = LightQuickFixTestCase.findActionWithText(getAvailableActions(), text); + + if (afterAction != null) { + fail("Action '" + text + "' is still available after its invocation in test " + testFullPath); + } + } + + checkResultByFile(name.replace("before", "after").replace(MAIN_SUBSTRING, "") + ".kt"); + } + } + + protected List getTestFiles() { + File dir = new File(getTestDataPath()); + + assertTrue("Main file should contain .Main. substring", name.contains(MAIN_SUBSTRING)); + final String testPrefix = name.replace(MAIN_SUBSTRING, ""); + + // Files of single test + FilenameFilter resultFilter = new FilenameFilter() { + @Override + public boolean accept(File file, String s) { + return s.contains(testPrefix) && !s.contains("after"); + } + }; + + List allTestFiles = Arrays.asList(dir.listFiles(resultFilter)); + + final Collection mainFiles = Collections2.filter(allTestFiles, new Predicate() { + @Override + public boolean apply(@Nullable File file) { + return file != null && file.getName().contains(MAIN_SUBSTRING); + } + }); + + assertTrue("No main file for test", mainFiles.size() > 0); + assertTrue("Too many main files for the test", mainFiles.size() <= 1); + + final Collection dataFiles = Collections2.filter(allTestFiles, new Predicate() { + @Override + public boolean apply(@Nullable File file) { + return file != null && file.getName().contains(DATA_SUBSTRING); + } + }); + + final ArrayList fileResult = new ArrayList(allTestFiles); + fileResult.addAll(dataFiles); + + return fileResult; + } + + protected static List getFileNames(List files) { + return Lists.newArrayList(Collections2.transform(files, new Function() { + @Override + public String apply(File file) { + return file.getName(); + } + })); + } + + protected List getAvailableActions() { + doHighlighting(); + return LightQuickFixTestCase.getAvailableActions(getEditor(), getFile()); + } + + @Override + public String getName() { + return "test" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase()); + } + + @Override + protected String getTestDataPath() { + return PluginTestCaseBase.getTestDataPathBase() + "/quickfix/" + dataPath + "/"; + } + + @Override + protected Sdk getTestProjectJdk() { + return PluginTestCaseBase.jdkFromIdeaHome(); + } + + public static boolean isMultiFileName(String fileName) { + return fileName.contains(MAIN_SUBSTRING) || fileName.contains(DATA_SUBSTRING); + } + + public static boolean isMainFile(String fileName) { + return fileName.contains(MAIN_SUBSTRING); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + + FilenameFilter multifileFileNameFilter = new FilenameFilter() { + @Override + public boolean accept(File file, String s) { + return s.startsWith("before") && JetPsiCheckerMultifileTest.isMainFile(s); + } + }; + + JetTestCaseBuilder.NamedTestFactory multiFileNamedTestFactory = new JetTestCaseBuilder.NamedTestFactory() { + @NotNull + @Override + public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { + return new JetPsiCheckerMultifileTest(dataPath, name); + } + }; + + File dir = new File(getTestDataPathBase()); + List subDirs = Arrays.asList(dir.list()); + Collections.sort(subDirs); + for (String subDirName : subDirs) { + final TestSuite multiFileTestSuite = JetTestCaseBuilder.suiteForDirectory(getTestDataPathBase(), subDirName, true, multifileFileNameFilter, multiFileNamedTestFactory); + if (multiFileTestSuite.countTestCases() != 0) { + suite.addTest(multiFileTestSuite); + } + } + return suite; + } + + public static String getTestDataPathBase() { + return JetTestCaseBuilder.getHomeDirectory() + "/idea/testData/quickfix/"; + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java index 62faeb23d10..044378f134d 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java @@ -43,26 +43,30 @@ public class JetQuickFixTest extends LightQuickFixTestCase { public static Test suite() { //setFilter(); //to launch only part of tests TestSuite suite = new TestSuite(); - FilenameFilter fileNameFilter = new FilenameFilter() { + + FilenameFilter singleFileNameFilter = new FilenameFilter() { @Override public boolean accept(File file, String s) { - if (s.startsWith("before")) return true; - return false; + return s.startsWith("before") && !JetPsiCheckerMultifileTest.isMultiFileName(s); } }; - JetTestCaseBuilder.NamedTestFactory namedTestFactory = new JetTestCaseBuilder.NamedTestFactory() { + + JetTestCaseBuilder.NamedTestFactory singleFileNamedTestFactory = new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override public Test createTest(@NotNull String dataPath, @NotNull String name, @NotNull File file) { return new JetQuickFixTest(dataPath, name); } }; + File dir = new File(getTestDataPathBase()); List subDirs = Arrays.asList(quickFixTestsFilter != null ? dir.list(quickFixTestsFilter) : dir.list()); Collections.sort(subDirs); for (String subDirName : subDirs) { - suite.addTest(JetTestCaseBuilder.suiteForDirectory(getTestDataPathBase(), subDirName, true, fileNameFilter, namedTestFactory)); - + final TestSuite singleFileTestSuite = JetTestCaseBuilder.suiteForDirectory(getTestDataPathBase(), subDirName, true, singleFileNameFilter, singleFileNamedTestFactory); + if (singleFileTestSuite.countTestCases() != 0) { + suite.addTest(singleFileTestSuite); + } } return suite; } diff --git a/stdlib.ipr b/stdlib.ipr new file mode 100644 index 00000000000..30c354500c5 --- /dev/null +++ b/stdlib.ipr @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + http://www.w3.org/1999/xhtml + + + + + + + + + diff --git a/stdlib/ktSrc/Filter.kt b/stdlib/ktSrc/Filter.kt new file mode 100644 index 00000000000..1fa5cb45317 --- /dev/null +++ b/stdlib/ktSrc/Filter.kt @@ -0,0 +1,66 @@ +namespace std + +import java.util.* +import java.lang.Iterable + +/* +Filters given iterator +*/ +inline fun java.util.Iterator.filter(f: fun(T): Boolean) : java.util.Iterator = FilterIterator(this, f) + +/* +Adds filtered elements in to given container +*/ +/* +inline fun > java.lang.Iterable.filterTo(var container: U, filter: fun(T): Boolean) : U { + for(element in this) { + if(filter(element)) + container.add(element) + } + return container +} +*/ + +/* +Create iterator filtering given java.lang.Iterable +*/ +/* +inline fun java.lang.Iterable.filter(f: fun(T): Boolean) : java.util.Iterator = (iterator() as java.util.Iterator).filter(f) +*/ + +private class FilterIterator(val original: java.util.Iterator, val filter: fun(T): Boolean) : java.util.Iterator { + var state = 0 + var nextElement: T? = null + + override fun hasNext(): Boolean = + when(state) { + 1 => true // checked and next present + 2 => false // checked and next not present + else => { + while(original.hasNext()) { + val candidate = original.next() + if((filter)(candidate)) { + nextElement = candidate + state = 1 + true + } + } + state = 2 + false + } + } + + override fun next(): T = + if(state != 1) + throw java.util.NoSuchElementException() + else { + val res = nextElement as T + nextElement = null + state = 0 + res + } + + override fun remove() { + throw java.lang.UnsupportedOperationException() + } +} diff --git a/stdlib/ktSrc/Iterators.kt b/stdlib/ktSrc/Iterators.kt new file mode 100644 index 00000000000..8a9b592ab26 --- /dev/null +++ b/stdlib/ktSrc/Iterators.kt @@ -0,0 +1,38 @@ +namespace std.util + +import java.util.* +import java.util.Iterator + +/* +Add iterated elements to given container +*/ +fun > java.util.Iterator.to(container: U) : U { + while(hasNext()) + container.add(next()) + return container +} + +/* +Add iterated elements to java.util.ArrayList +*/ +inline fun java.util.Iterator.toArrayList() = to(ArrayList()) + +/* +Add iterated elements to java.util.LinkedList +*/ +inline fun java.util.Iterator.toLinkedList() = to(LinkedList()) + +/* +Add iterated elements to java.util.HashSet +*/ +inline fun java.util.Iterator.toHashSet() = to(HashSet()) + +/* +Add iterated elements to java.util.LinkedHashSet +*/ +inline fun java.util.Iterator.toLinkedHashSet() = to(LinkedHashSet()) + +/* +Add iterated elements to java.util.TreeSet +*/ +inline fun java.util.Iterator.toTreeSet() = to(TreeSet()) diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index a75df8656d9..c9ef555cf0d 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -2,8 +2,212 @@ namespace std.util import java.util.* +/** Returns the size of the collection */ val Collection<*>.size : Int get() = size() +/** Returns true if this collection is empty */ val Collection<*>.empty : Boolean get() = isEmpty() + +/** Returns a new ArrayList with a variable number of initial elements */ +inline fun arrayList(vararg values: T) : ArrayList { + val answer = ArrayList() + for (v in values) + answer.add(v) + return answer; +} + +/** Returns a new LinkedList with a variable number of initial elements */ +inline fun linkedList(vararg values: T) : LinkedList { + val answer = LinkedList() + for (v in values) + answer.add(v) + return answer; +} + +/** Returns a new HashSet with a variable number of initial elements */ +inline fun hashSet(vararg values: T) : HashSet { + val answer = HashSet() + for (v in values) + answer.add(v) + return answer; +} + +/** Returns true if any elements in the collection match the given predicate */ +inline fun java.lang.Iterable.any(predicate: fun(T): Boolean) : Boolean { + for (elem in this) { + if (predicate(elem)) { + return true + } + } + return false +} + +/** Returns true if all elements in the collection match the given predicate */ +inline fun java.lang.Iterable.all(predicate: fun(T): Boolean) : Boolean { + for (elem in this) { + if (!predicate(elem)) { + return false + } + } + return true +} + +/** Returns the first item in the collection which matches the given predicate or null if none matched */ +inline fun java.lang.Iterable.find(predicate: fun(T): Boolean) : T? { + for (elem in this) { + if (predicate(elem)) + return elem + } + return null +} + +/** Returns a new collection containing all elements in this collection which match the given predicate */ +inline fun java.lang.Iterable.filter(result: Collection = ArrayList(), predicate: fun(T): Boolean) : Collection { + for (elem in this) { + if (predicate(elem)) + result.add(elem) + } + return result +} + +/** + * Returns the result of transforming each item in the collection to a one or more values which + * are concatenated together into a single collection + */ +inline fun java.lang.Iterable.flatMap(result: Collection = ArrayList(), transform: fun(T): Collection) : Collection { + for (elem in this) { + val coll = transform(elem) + if (coll != null) { + for (r in coll) { + result.add(r) + } + } + } + return result +} + +/** Performs the given operation on each element inside the collection */ +inline fun java.lang.Iterable.foreach(operation: fun(element: T) : Unit) { + for (elem in this) + operation(elem) +} + +/** Creates a String from all the elements in the collection, using the seperator between them and using the given prefix and postfix if supplied */ +inline fun java.lang.Iterable.join(separator: String, prefix: String = "", postfix: String = "") : String { + val buffer = StringBuilder(prefix) + var first = true + for (elem in this) { + if (first) + first = false + else + buffer.append(separator) + buffer.append(elem) + } + buffer.append(postfix) + return buffer.toString().sure() +} + +/** Returns a new collection containing the results of applying the given function to each element in this collection */ +inline fun java.lang.Iterable.map(result: Collection = ArrayList(), transform : fun(T) : R) : Collection { + for (item in this) + result.add(transform(item)) + return result +} + +/** Returns a new collection containing the results of applying the given function to each element in this collection */ +inline fun java.util.Collection.map(result: Collection = ArrayList(this.size), transform : fun(T) : R) : Collection { + for (item in this) + result.add(transform(item)) + return result +} + +inline fun > java.lang.Iterable.toSortedList() : List { + val answer = this.toList() + answer.sort() + return answer +} + +inline fun > java.lang.Iterable.toSortedList(comparator: java.util.Comparator) : List { + val answer = this.toList() + answer.sort(comparator) + return answer +} + +/** + TODO figure out necessary variance/generics ninja stuff... :) +inline fun java.lang.Iterable.toSortedList(transform: fun(T) : java.lang.Comparable<*>) : List { + val answer = this.toList() + answer.sort(transform) + return answer +} +*/ + +inline fun java.lang.Iterable.toList() : List { + if (this is List) + return this + else { + val list = ArrayList() + for (elem in this) + list.add(elem) + return list + } +} + +inline fun java.util.Collection.toArray() : Array { + if (this is Array) + return this + else { + val answer = Array(this.size) + var idx = 0 + for (elem in this) + answer[idx++] = elem + return answer as Array + } +} + + +// List APIs + +inline fun > List.sort() : Unit { + Collections.sort(this) +} + +inline fun > List.sort(comparator: java.util.Comparator) : Unit { + Collections.sort(this, comparator) +} + +/** + TODO figure out necessary variance/generics ninja stuff... :) +inline fun List.sort(transform: fun(T) : java.lang.Comparable<*>) : List { + val comparator = java.util.Comparator() { + fun compare(o1: T, o2: T): Int { + val v1 = transform(o1) + val v2 = transform(o2) + if (v1 == v2) { + return 0 + } else { + return v1.compareTo(v2) + } + } + } + answer.sort(comparator) +} +*/ + +val List.head : T? + get() = this.get(0) + +val List.first : T? + get() = this.head + +val List.tail : T? + get() { + val s = this.size + return if (s > 0) this.get(s - 1) else null + + } +val List.last : T? + get() = this.tail + diff --git a/stdlib/ktSrc/System.kt b/stdlib/ktSrc/System.kt new file mode 100644 index 00000000000..1b5545f0266 --- /dev/null +++ b/stdlib/ktSrc/System.kt @@ -0,0 +1,19 @@ +namespace std.util + +/** +Executes current block and returns elapsed time in milliseconds +*/ +fun measureTimeMillis(block: fun() : Unit) : Long { + val start = System.currentTimeMillis() + block() + return System.currentTimeMillis() - start +} + +/** +Executes current block and returns elapsed time in milliseconds +*/ +fun measureTimeNano(block: fun() : Unit) : Long { + val start = System.nanoTime() + block() + return System.nanoTime() - start +} \ No newline at end of file diff --git a/stdlib/ktSrc/Thread.kt b/stdlib/ktSrc/Thread.kt new file mode 100644 index 00000000000..637418ea902 --- /dev/null +++ b/stdlib/ktSrc/Thread.kt @@ -0,0 +1,41 @@ +namespace std.concurrent + +import java.lang.* + +inline var Thread.name : String + get() = getName().sure() + set(name: String) { setName(name) } + +inline var Thread.daemon : Boolean + get() = isDaemon() + set(on: Boolean) { setDaemon(on) } + +inline val Thread.alive : Boolean + get() = isAlive() + +inline var Thread.priority : Int + get() = getPriority() + set(prio: Int) { setPriority(prio) } + +inline var Thread.contextClassLoader : ClassLoader? + get() = getContextClassLoader() + set(loader: ClassLoader?) { setContextClassLoader(loader) } + +fun thread(start: Boolean = true, daemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority: Int = -1, block: fun():Unit) : Thread { + val thread = object: Thread() { + override fun run() { + block() + } + } + if(daemon) + thread.setDaemon(true) + if(priority > 0) + thread.setPriority(priority) + if(name != null) + thread.setName(name) + if(contextClassLoader != null) + thread.setContextClassLoader(contextClassLoader) + if(start) + thread.start() + return thread +} diff --git a/stdlib/src/jet/BooleanIterable.java b/stdlib/src/jet/BooleanIterable.java new file mode 100644 index 00000000000..76d59748d65 --- /dev/null +++ b/stdlib/src/jet/BooleanIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface BooleanIterable extends Iterable { + @Override + BooleanIterator iterator(); +} diff --git a/stdlib/src/jet/ByteIterable.java b/stdlib/src/jet/ByteIterable.java new file mode 100644 index 00000000000..36e773da574 --- /dev/null +++ b/stdlib/src/jet/ByteIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface ByteIterable extends Iterable { + @Override + ByteIterator iterator(); +} diff --git a/stdlib/src/jet/CharIterable.java b/stdlib/src/jet/CharIterable.java new file mode 100644 index 00000000000..d8646e449f3 --- /dev/null +++ b/stdlib/src/jet/CharIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface CharIterable extends Iterable { + @Override + CharIterator iterator(); +} diff --git a/stdlib/src/jet/DoubleIterable.java b/stdlib/src/jet/DoubleIterable.java new file mode 100644 index 00000000000..ac6336039a2 --- /dev/null +++ b/stdlib/src/jet/DoubleIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface DoubleIterable extends Iterable { + @Override + DoubleIterator iterator(); +} diff --git a/stdlib/src/jet/FloatIterable.java b/stdlib/src/jet/FloatIterable.java new file mode 100644 index 00000000000..5bbd25f3dd9 --- /dev/null +++ b/stdlib/src/jet/FloatIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface FloatIterable extends Iterable { + @Override + FloatIterator iterator(); +} diff --git a/stdlib/src/jet/IntIterable.java b/stdlib/src/jet/IntIterable.java new file mode 100644 index 00000000000..0963ba1f099 --- /dev/null +++ b/stdlib/src/jet/IntIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface IntIterable extends Iterable { + @Override + IntIterator iterator(); +} diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index 13811dbba40..7866919f9fe 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -2,7 +2,7 @@ package jet; import jet.typeinfo.TypeInfo; -public final class IntRange implements Range, Iterable, JetObject { +public final class IntRange implements Range, IntIterable, JetObject { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); private final int start; @@ -39,7 +39,7 @@ public final class IntRange implements Range, Iterable, JetObj } @Override - public Iterator iterator() { + public IntIterator iterator() { return new MyIterator(start, count); } @@ -66,7 +66,7 @@ public final class IntRange implements Range, Iterable, JetObj } } - private static class MyIterator implements Iterator { + private static class MyIterator extends IntIterator { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); private int cur; @@ -86,7 +86,7 @@ public final class IntRange implements Range, Iterable, JetObj } @Override - public Integer next() { + public int nextInt() { count--; if(reversed) { return cur--; diff --git a/stdlib/src/jet/LongIterable.java b/stdlib/src/jet/LongIterable.java new file mode 100644 index 00000000000..79567c0604b --- /dev/null +++ b/stdlib/src/jet/LongIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface LongIterable extends Iterable { + @Override + LongIterator iterator(); +} diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java index ed94c76cb31..dea5c70402e 100644 --- a/stdlib/src/jet/LongRange.java +++ b/stdlib/src/jet/LongRange.java @@ -2,7 +2,7 @@ package jet; import jet.typeinfo.TypeInfo; -public final class LongRange implements Range, Iterable, JetObject { +public final class LongRange implements Range, LongIterable, JetObject { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(IntRange.class, false); private final long start; @@ -39,7 +39,7 @@ public final class LongRange implements Range, Iterable, JetObject { } @Override - public Iterator iterator() { + public LongIterator iterator() { return new MyIterator(start, count); } @@ -66,7 +66,7 @@ public final class LongRange implements Range, Iterable, JetObject { } } - private static class MyIterator implements Iterator { + private static class MyIterator extends LongIterator { private final static TypeInfo typeInfo = TypeInfo.getTypeInfo(MyIterator.class, false); private long cur; @@ -86,7 +86,7 @@ public final class LongRange implements Range, Iterable, JetObject { } @Override - public Long next() { + public long nextLong() { count--; if(reversed) { return cur--; diff --git a/stdlib/src/jet/ShortIterable.java b/stdlib/src/jet/ShortIterable.java new file mode 100644 index 00000000000..9da1721794b --- /dev/null +++ b/stdlib/src/jet/ShortIterable.java @@ -0,0 +1,9 @@ +package jet; + +/** + * @author alex.tkachman + */ +public interface ShortIterable extends Iterable { + @Override + ShortIterator iterator(); +} diff --git a/stdlib/src/jet/runtime/Intrinsics.java b/stdlib/src/jet/runtime/Intrinsics.java index 19488b98ba2..d9a8f68ef7b 100644 --- a/stdlib/src/jet/runtime/Intrinsics.java +++ b/stdlib/src/jet/runtime/Intrinsics.java @@ -1,5 +1,7 @@ package jet.runtime; +import jet.Function0; + import java.util.ArrayList; /** @@ -29,6 +31,12 @@ public class Intrinsics { return (thisVal == anotherVal ? 0 : (anotherVal ? 1 : -1)); } + public static R stupidSync(Object lock, Function0 block) { + synchronized (lock) { + return block.invoke(); + } + } + private static Throwable sanitizeStackTrace(Throwable throwable) { StackTraceElement[] stackTrace = throwable.getStackTrace(); ArrayList list = new ArrayList(); diff --git a/stdlib/src/jet/typeinfo/JetValueParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java index db0a4f52605..cc3b7aebbf0 100644 --- a/stdlib/src/jet/typeinfo/JetValueParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -35,6 +35,11 @@ public @interface JetValueParameter { */ boolean hasDefaultValue () default false; + /** + * @return if this parameter is receiver + */ + boolean receiver() default false; + /** * @return type unless Java type is correct Kotlin type. */ diff --git a/testlib/lib/junit-4.9.jar b/testlib/lib/junit-4.9.jar new file mode 100644 index 00000000000..14208156115 Binary files /dev/null and b/testlib/lib/junit-4.9.jar differ diff --git a/testlib/src/Test.kt b/testlib/src/Test.kt new file mode 100644 index 00000000000..b586a0ff4e3 --- /dev/null +++ b/testlib/src/Test.kt @@ -0,0 +1,69 @@ +namespace std.test + +import std.io.* +import std.util.* +import java.util.* + +import org.junit.* +import org.junit.runner.* +import org.junit.runner.notification.* +import junit.framework.* + +fun assert(message: String, block: fun() : Boolean) { + val actual = block() + Assert.assertTrue(message, actual) +} + +fun assert(block: fun() : Boolean) = assert(block.toString(), block) + +fun assertNot(message: String, block: fun() : Boolean) { + assert(message){ !block() } +} + +fun assertNot(block: fun() : Boolean) = assertNot(block.toString(), block) + +fun assert(actual: Boolean, message: String) { + println("Answer: ${actual} for ${message}") +} + +fun assertEquals(expected: Any, actual: Any?, message: String = "") { + Assert.assertEquals(message, expected, actual) +} + +fun assertNull(actual: Any?, message: String = "") { + Assert.assertNull(message, actual) +} + +fun fails(block: fun() : Any) { + try { + block() + Assert.fail("Expected an exception to be thrown") + } catch (e: Exception) { + // OK + } +} + +fun todo(block: fun(): Any) { + println("TODO at " + Exception().getStackTrace()?.get(1)) +} + +/* +TODO we could maybe create our own test runner for JUnit +to avoid a runtime dependency on JUnit for running tests? + +class KotlinTestRunner() : Runner() { + + override fun getDescription(): Description? { + return null + } + + override fun run(notifier: RunNotifier?) { + println("About to run a test case on ${this}") + } +} +*/ + +// TODO no annotations yet? +//@RunWith(KotlinTestRunner) +abstract class TestSupport() : TestCase() { +} \ No newline at end of file diff --git a/testlib/test/CollectionApiCheck.kt b/testlib/test/CollectionApiCheck.kt new file mode 100644 index 00000000000..4396cc2617d --- /dev/null +++ b/testlib/test/CollectionApiCheck.kt @@ -0,0 +1,35 @@ +namespace test.apicheck + +import std.util.* +import java.util.* + +trait Traversable { + + /** Returns true if any elements in the collection match the given predicate */ + fun any(predicate: fun(T): Boolean) : Boolean + + /** Returns true if all elements in the collection match the given predicate */ + fun all(predicate: fun(T): Boolean) : Boolean + + /** Returns the first item in the collection which matches the given predicate or null if none matched */ + fun find(predicate: fun(T): Boolean) : T? + + /** Returns a new collection containing all elements in this collection which match the given predicate */ + // TODO using: Collection for the return type - I wonder if this exact type could be + // deduced somewhat from the This.Type; e.g. returning Set on a Set, Array on Array etc + fun filter(predicate: fun(T): Boolean) : Collection + + /** Performs the given operation on each element inside the collection */ + fun foreach(operation: fun(element: T) : Unit) + + /** Returns a new collection containing the results of applying the given function to each element in this collection */ + fun java.lang.Iterable.map(transform : fun(T) : R) : Collection +} + +/** +TODO try use delegation here to make sure we implement all the methods in the Traversable API + +class ListImpl(coll: ArrayList) : Traversable by coll { +} + +*/ \ No newline at end of file diff --git a/testlib/test/CollectionTest.kt b/testlib/test/CollectionTest.kt new file mode 100644 index 00000000000..3768820f61a --- /dev/null +++ b/testlib/test/CollectionTest.kt @@ -0,0 +1,153 @@ +namespace test.collections + +// TODO can we avoid importing all this stuff by default I wonder? +// e.g. making println and the collection builder methods public by default? +import std.* +import std.io.* +import std.util.* +import std.test.* +import java.util.* + +class CollectionTest() : TestSupport() { + val data = arrayList("foo", "bar") + + fun testAny() { + assert { + data.any{it.startsWith("f")} + } + assertNot { + data.any{it.startsWith("x")} + } + } + + fun testAll() { + assert { + data.all{it.length == 3} + } + assertNot { + data.all{s => s.startsWith("b")} + } + } + + fun testFilter() { + val foo = data.filter{it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(arrayList("foo"), foo) + } + + fun testFilterIntoLinkedList() { + // TODO would be nice to avoid the + val foo = data.filter(linkedList()){it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(linkedList("foo"), foo) + + assert { + foo is LinkedList + } + } + + fun testFilterIntoSortedSet() { + // TODO would be nice to avoid the + val foo = data.filter(hashSet()){it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(hashSet("foo"), foo) + + assert { + foo is HashSet + } + } + + fun testFind() { + val x = data.find{it.startsWith("x")} + assertNull(x) + fails { + x.sure() + } + + val f = data.find{it.startsWith("f")} + f.sure() + assertEquals("foo", f) + } + + fun testFlatMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + // TODO there should be a neater way to do this :) + + val characters = arrayList('f', 'o', 'o', 'b', 'a', 'r') + /* + val characters = data.flatMap{ + Arrays.asList((it as java.lang.String).toCharArray()) as Collection + } + */ + todo { + println("Got list of characters ${characters}") + val text = characters.join("") + assertEquals("foobar", text) + } + } + + fun testForeach() { + var count = 0 + val x = data.foreach{ count += it.length } + assertEquals(6, count) + } + + fun testJoin() { + val text = data.join("-", "<", ">") + assertEquals("", text) + } + + fun testMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + val lengths = data.map{s => s.length} + assert { + lengths.all{it == 3} + } + assertEquals(2, lengths.size) + assertEquals(arrayList(3, 3), lengths) + } + + fun testSort() { + val coll: List = arrayList("foo", "bar", "abc") + + // TODO fixme + // Some sort of in/out variance thing - or an issue with Java interop? + //coll.sort() + todo { + assertEquals(3, coll.size) + assertEquals(arrayList("abc", "bar", "foo"), coll) + + } + } + + fun testToArray() { + val arr = data.toArray() + println("Got array ${arr}") + todo { + assert { + arr is Array + } + } + } + +} \ No newline at end of file diff --git a/testlib/test/ListTest.kt b/testlib/test/ListTest.kt new file mode 100644 index 00000000000..85ea7007ba9 --- /dev/null +++ b/testlib/test/ListTest.kt @@ -0,0 +1,30 @@ +namespace test.collections + +import std.test.* + +// TODO can we avoid importing all this stuff by default I wonder? +// e.g. making println and the collection builder methods public by default? +import std.* +import std.io.* +import std.util.* +import java.util.* + +class ListTest() : TestSupport() { + val data = arrayList("foo", "bar") + + fun testHeadAndTail() { + val h = data.head + assertEquals("foo", h) + + val t = data.tail + assertEquals("bar", t) + } + + fun testFirstAndLast() { + val h = data.first + assertEquals("foo", h) + + val t = data.last + assertEquals("bar", t) + } +} \ No newline at end of file diff --git a/testlib/test/SetTest.kt b/testlib/test/SetTest.kt new file mode 100644 index 00000000000..3ae835dd029 --- /dev/null +++ b/testlib/test/SetTest.kt @@ -0,0 +1,73 @@ +namespace test.collections + +import std.* +import std.io.* +import std.util.* +import std.test.* +import java.util.* + +class SetTest() : TestSupport() { + val data = hashSet("foo", "bar") + + fun testAny() { + assert { + data.any{it.startsWith("f")} + } + assertNot { + data.any{it.startsWith("x")} + } + } + + fun testAll() { + assert { + data.all{it.length == 3} + } + assertNot { + data.all{s => s.startsWith("b")} + } + } + + fun testFilter() { + val foo = data.filter{it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(arrayList("foo"), foo) + + // TODO ideally foo would now be a set + todo { + assert("Filter on a Set should return a Set") { + foo is Set + } + } + } + + fun testFind() { + val x = data.find{it.startsWith("x")} + assertNull(x) + fails { + x.sure() + } + + val f = data.find{it.startsWith("f")} + f.sure() + assertEquals("foo", f) + } + + fun testMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + val lengths = data.map{s => s.length} + assert { + lengths.all{it == 3} + } + assertEquals(2, lengths.size) + assertEquals(arrayList(3, 3), lengths) + } + +} \ No newline at end of file diff --git a/testlib/testlib.iml b/testlib/testlib.iml new file mode 100644 index 00000000000..d1780f417e7 --- /dev/null +++ b/testlib/testlib.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + +