diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java new file mode 100644 index 00000000000..f2cb8838b1d --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -0,0 +1,215 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.signature.JetSignatureWriter; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; +import org.objectweb.asm.util.CheckSignatureAdapter; + +import java.util.Stack; + +/** + * @author Stepan Koltsov + */ +public class BothSignatureWriter { + + private static final boolean DEBUG_SIGNATURE_WRITER = true; + + enum Mode { + METHOD(CheckSignatureAdapter.METHOD_SIGNATURE), + CLASS(CheckSignatureAdapter.CLASS_SIGNATURE), + ; + + private final int asmType; + + Mode(int asmType) { + this.asmType = asmType; + } + } + + private final SignatureWriter signatureWriter = new SignatureWriter(); + private final SignatureVisitor signatureVisitor; + + private final JetSignatureWriter jetSignatureWriter = new JetSignatureWriter(); + + private final Mode mode; + + public BothSignatureWriter(Mode mode) { + this.mode = mode; + if (DEBUG_SIGNATURE_WRITER) { + signatureVisitor = new CheckSignatureAdapter(mode.asmType, signatureWriter); + } else { + signatureVisitor = signatureWriter; + } + } + + // TODO: ignore when debugging is disabled + private Stack visitors = new Stack(); + + private void push(SignatureVisitor visitor) { + visitors.push(visitor); + } + + private void pop() { + visitors.pop(); + } + + + + private SignatureVisitor signatureVisitor() { + return !visitors.isEmpty() ? visitors.peek() : signatureVisitor; + } + + private void checkTopLevel() { + if (DEBUG_SIGNATURE_WRITER) { + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + } + + private void checkMode(Mode mode) { + if (DEBUG_SIGNATURE_WRITER) { + if (mode != this.mode) { + throw new IllegalStateException(); + } + } + } + + + /** + * Shortcut + */ + public void writeAsmType(Type asmType) { + switch (asmType.getSort()) { + case Type.OBJECT: + writeClassBegin(asmType.getInternalName()); + writeClassEnd(); + return; + case Type.ARRAY: + writeArrayType(); + writeAsmType(asmType.getElementType()); + writeArrayEnd(); + return; + default: + String descriptor = asmType.getDescriptor(); + if (descriptor.length() != 1) { + throw new IllegalStateException(); + } + signatureVisitor().visitBaseType(descriptor.charAt(0)); + } + } + + public void writeClassBegin(String internalName) { + signatureVisitor().visitClassType(internalName); + } + + public void writeClassEnd() { + signatureVisitor().visitEnd(); + } + + public void writeArrayType() { + push(signatureVisitor().visitArrayType()); + } + + public void writeArrayEnd() { + pop(); + } + + public void writeTypeArgument(char c) { + push(signatureVisitor().visitTypeArgument(c)); + } + + public void writeTypeArgumentEnd() { + pop(); + } + + public void writeTypeVariable(final String name) { + signatureVisitor().visitTypeVariable(name); + } + + public void writeFormalTypeParameter(final String name) { + checkTopLevel(); + + signatureVisitor().visitFormalTypeParameter(name); + } + + public void writeClassBound() { + push(signatureVisitor().visitClassBound()); + } + + public void writeClassBoundEnd() { + pop(); + } + + public void writeInterfaceBound() { + push(signatureVisitor().visitInterfaceBound()); + } + + public void writeInterfaceBoundEnd() { + pop(); + } + + public void writeParameterType() { + push(signatureVisitor().visitParameterType()); + } + + public void writeParameterTypeEnd() { + pop(); + } + + public void writeReturnType() { + push(signatureVisitor().visitReturnType()); + } + + public void writeReturnTypeEnd() { + pop(); + } + + public void writeSuperclass() { + checkTopLevel(); + checkMode(Mode.CLASS); + + push(signatureVisitor().visitSuperclass()); + } + + public void writeSuperclassEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + public void writeInterface() { + checkTopLevel(); + checkMode(Mode.CLASS); + + push(signatureVisitor().visitInterface()); + } + + public void writeInterfaceEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + + + + @Nullable + public String makeJavaString() { + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + return signatureWriter.toString(); + } + + @Nullable + public String makeKotlinString() { + // TODO: not implemented yet + return null; + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 53af0cdc730..1b1bb5db25c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -57,26 +57,18 @@ public class CodegenUtil { return (ClassDescriptor) outerDescriptor; } - public static boolean hasOuterTypeInfo(ClassDescriptor descriptor) { - ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(descriptor); - if(outerClassDescriptor == null) - return false; - - if(outerClassDescriptor.getTypeConstructor().getParameters().size() > 0) - return true; - - return hasOuterTypeInfo(outerClassDescriptor); - } - - public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) { - if(!exceptOwn) { - if(!isInterface(type)) - if(hasTypeInfoField(type)) - return true; + public static boolean hasDerivedTypeInfoField(JetType type) { + for (JetType jetType : type.getConstructor().getSupertypes()) { + if(hasTypeInfoField(jetType)) + return true; } - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(hasDerivedTypeInfoField(jetType, false)) + return false; + } + + public static boolean requireTypeInfoConstructorArg(JetType type) { + for (TypeParameterDescriptor parameter : type.getConstructor().getParameters()) { + if(parameter.isReified()) return true; } @@ -87,22 +79,10 @@ public class CodegenUtil { if(isInterface(type)) return false; - List parameters = type.getConstructor().getParameters(); - for (TypeParameterDescriptor parameter : parameters) { - if(parameter.isReified()) - return true; - } + if(requireTypeInfoConstructorArg(type)) + return true; - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(hasTypeInfoField(jetType)) - return true; - } - - ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor()); - if(outerClassDescriptor == null || isClassObject(type.getConstructor().getDeclarationDescriptor())) - return false; - - return hasTypeInfoField(outerClassDescriptor.getDefaultType()); + return hasDerivedTypeInfoField(type); } public static FunctionDescriptor createInvoke(ExpressionAsFunctionDescriptor fd) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java index b27e9ab18ce..9c60a5b170e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java @@ -12,11 +12,11 @@ import java.util.List; /** * @author yole + * @author alex.tkachman */ public class ConstructorFrameMap extends FrameMap { private int myOuterThisIndex = -1; - private int myFirstTypeParameter = -1; - private int myTypeParameterCount = 0; + private int myTypeInfoIndex = -1; public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, ClassDescriptor classDescriptor, OwnerKind kind) { enterTemp(); // this @@ -27,15 +27,8 @@ public class ConstructorFrameMap extends FrameMap { } if (classDescriptor != null) { - List parameters = classDescriptor.getTypeConstructor().getParameters(); - for (TypeParameterDescriptor parameter : parameters) { - if(parameter.isReified()) { - int index = enterTemp(); - myTypeParameterCount++; - if(myFirstTypeParameter == -1) { - myFirstTypeParameter = index; - } - } + if (CodegenUtil.requireTypeInfoConstructorArg(classDescriptor.getDefaultType())) { + myTypeInfoIndex = enterTemp(); } } @@ -54,11 +47,7 @@ public class ConstructorFrameMap extends FrameMap { return myOuterThisIndex; } - public int getFirstTypeParameter() { - return myFirstTypeParameter; - } - - public int getTypeParameterCount() { - return myTypeParameterCount; + public int getTypeInfoIndex() { + return myTypeInfoIndex; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a24e486308e..b8628fbc7c0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -979,7 +979,7 @@ public class ExpressionCodegen extends JetVisitor { } else if (descriptor instanceof TypeParameterDescriptor) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor; - loadTypeParameterTypeInfo(typeParameterDescriptor); + loadTypeParameterTypeInfo(typeParameterDescriptor, null); v.invokevirtual("jet/typeinfo/TypeInfo", "getClassObject", "()Ljava/lang/Object;"); v.checkcast(asmType(typeParameterDescriptor.getClassObjectType())); @@ -2033,26 +2033,32 @@ public class ExpressionCodegen extends JetVisitor { private void pushTypeArguments(ResolvedCall resolvedCall) { if(resolvedCall != null) { - Map typeArguments = resolvedCall.getTypeArguments(); - CallableDescriptor resultingDescriptor = resolvedCall.getCandidateDescriptor(); - for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) { - if(typeParameterDescriptor.isReified()) { - JetType jetType = typeArguments.get(typeParameterDescriptor); - generateTypeInfo(jetType); + if(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor) { + ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); + ClassDescriptor containingDeclaration = constructorDescriptor.getContainingDeclaration(); + if(CodegenUtil.requireTypeInfoConstructorArg(containingDeclaration.getDefaultType())) { + generateTypeInfo(containingDeclaration.getDefaultType(), resolvedCall.getTypeArguments()); + } + } + else { + Map typeArguments = resolvedCall.getTypeArguments(); + CallableDescriptor resultingDescriptor = resolvedCall.getCandidateDescriptor(); + for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) { + if(typeParameterDescriptor.isReified()) { + JetType jetType = typeArguments.get(typeParameterDescriptor); + generateTypeInfo(jetType, typeArguments); + } } } } else { throw new UnsupportedOperationException(); -// for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) { -// pushTypeArgument(jetTypeArgument); -// } } } public void pushTypeArgument(JetTypeProjection jetTypeArgument) { JetType typeArgument = bindingContext.get(BindingContext.TYPE, jetTypeArgument.getTypeReference()); - generateTypeInfo(typeArgument); + generateTypeInfo(typeArgument, null); } private Type generateJavaConstructorCall(JetCallExpression expression) { @@ -2091,7 +2097,7 @@ public class ExpressionCodegen extends JetVisitor { if(isArray) { JetType elementType = typeMapper.getGenericsElementType(arrayType); if(elementType != null) { - generateTypeInfo(elementType); + generateTypeInfo(elementType, null); gen(args.get(0).getArgumentExpression(), Type.INT_TYPE); v.invokevirtual("jet/typeinfo/TypeInfo", "newArray", "(I)[Ljava/lang/Object;"); } @@ -2193,9 +2199,9 @@ public class ExpressionCodegen extends JetVisitor { if(getterDescriptor.getReceiverParameter().exists()) { index++; } - for (TypeParameterDescriptor typeParameterDescriptor : getterDescriptor.getTypeParameters()) { + for (TypeParameterDescriptor typeParameterDescriptor : resolvedGetCall.getCandidateDescriptor().getTypeParameters()) { if(typeParameterDescriptor.isReified()) { - generateTypeInfo(resolvedGetCall.getTypeArguments().get(typeParameterDescriptor)); + generateTypeInfo(resolvedGetCall.getTypeArguments().get(typeParameterDescriptor), null); index++; } } @@ -2215,7 +2221,7 @@ public class ExpressionCodegen extends JetVisitor { } for (TypeParameterDescriptor typeParameterDescriptor : setterDescriptor.getOriginal().getTypeParameters()) { if(typeParameterDescriptor.isReified()) { - generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor)); + generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor), null); index++; } } @@ -2503,7 +2509,7 @@ If finally block is present, its last expression is the value of try expression. } } else { - generateTypeInfo(jetType); + generateTypeInfo(jetType, null); expressionToGen.put(TYPE_OBJECT, v); if (leaveExpressionOnStack) { v.dupX1(); @@ -2512,7 +2518,7 @@ If finally block is present, its last expression is the value of try expression. } } - public void generateTypeInfo(JetType jetType) { + public void generateTypeInfo(JetType jetType, Map typeArguments) { String knownTypeInfo = typeMapper.isKnownTypeInfo(jetType); if(knownTypeInfo != null) { v.getstatic("jet/typeinfo/TypeInfo", knownTypeInfo, "Ljet/typeinfo/TypeInfo;"); @@ -2521,7 +2527,7 @@ If finally block is present, its last expression is the value of try expression. DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor(); if (declarationDescriptor instanceof TypeParameterDescriptor) { - loadTypeParameterTypeInfo((TypeParameterDescriptor) declarationDescriptor); + loadTypeParameterTypeInfo((TypeParameterDescriptor) declarationDescriptor, typeArguments); return; } @@ -2551,7 +2557,7 @@ If finally block is present, its last expression is the value of try expression. TypeProjection argument = arguments.get(i); v.dup(); v.iconst(i); - generateTypeInfo(argument.getType()); + generateTypeInfo(argument.getType(), typeArguments); genTypeInfoToProjection(v, argument.getProjectionKind()); v.astore(TYPE_OBJECT); } @@ -2573,12 +2579,21 @@ If finally block is present, its last expression is the value of try expression. throw new UnsupportedOperationException(variance.toString()); } - private void loadTypeParameterTypeInfo(TypeParameterDescriptor typeParameterDescriptor) { + private void loadTypeParameterTypeInfo(TypeParameterDescriptor typeParameterDescriptor, @Nullable Map typeArguments) { final StackValue value = typeParameterExpressions.get(typeParameterDescriptor); if (value != null) { value.put(TYPE_TYPEINFO, v); return; } + + if(typeArguments != null) { + JetType jetType = typeArguments.get(typeParameterDescriptor); + if(jetType != null && !jetType.equals(typeParameterDescriptor.getDefaultType())) { + generateTypeInfo(jetType, typeArguments); + return; + } + } + DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); if (context.getThisDescriptor() != null) { ClassDescriptor descriptor = context.getThisDescriptor(); @@ -2589,8 +2604,13 @@ If finally block is present, its last expression is the value of try expression. if (containingDeclaration == context.getThisDescriptor()) { if(!CodegenUtil.isInterface(descriptor)) { if (CodegenUtil.hasTypeInfoField(defaultType)) { - v.load(0, TYPE_OBJECT); - v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + if(!(context instanceof CodegenContext.ConstructorContext)) { + v.load(0, TYPE_OBJECT); + v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + else { + v.load(((ConstructorFrameMap)myFrameMap).getTypeInfoIndex(), TYPE_OBJECT); + } } else { v.getstatic(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); @@ -2598,16 +2618,16 @@ If finally block is present, its last expression is the value of try expression. } else { v.load(0, TYPE_OBJECT); - v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); + v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); } } else { v.load(0, TYPE_OBJECT); - v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); while(descriptor != containingDeclaration) { descriptor = CodegenUtil.getOuterClassDescriptor(descriptor); - v.invokevirtual("jet/typeinfo/TypeInfo", "getOuterTypeInfo", "()Ljet/typeinfo/TypeInfo;"); + v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getOuterObject", "()Ljet/JetObject;"); } + v.invokeinterface(TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); } v.aconst(ownerType); v.iconst(typeParameterDescriptor.getIndex()); @@ -2737,7 +2757,7 @@ If finally block is present, its last expression is the value of try expression. v.anew(tupleType); v.dup(); - generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression))); + generateTypeInfo(new ProjectionErasingJetType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression)), null); for (JetExpression entry : entries) { gen(entry, TYPE_OBJECT); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 24918f4c652..ab951d0e173 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.StdlibNames; +import org.jetbrains.jet.lang.resolve.java.StdlibNames; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; @@ -86,7 +86,7 @@ public class FunctionCodegen { if(v.generateCode()) { int start = 0; if(kind != OwnerKind.TRAIT_IMPL) { - AnnotationVisitor av = mv.visitAnnotation(StdlibNames.JET_METHOD_TYPE.getDescriptor(), true); + AnnotationVisitor av = mv.visitAnnotation(JetTypeMapper.JET_METHOD_TYPE.getDescriptor(), true); if(functionDescriptor.getReturnType().isNullable()) { av.visit(StdlibNames.JET_METHOD_NULLABLE_RETURN_TYPE_FIELD, true); } @@ -94,15 +94,15 @@ public class FunctionCodegen { } if(kind == OwnerKind.TRAIT_IMPL) { - AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, "this$self"); + AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, "this$self"); av.visitEnd(); } if(receiverParameter.exists()) { - AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, "this$receiver"); + AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, "this$receiver"); if(receiverParameter.getType().isNullable()) { - av.visit(StdlibNames.JET_PARAMETER_NULLABLE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } av.visitEnd(); } @@ -112,14 +112,14 @@ public class FunctionCodegen { av.visitEnd(); } for(int i = 0; i != paramDescrs.size(); ++i) { - AnnotationVisitor av = mv.visitParameterAnnotation(i + start, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); + AnnotationVisitor av = mv.visitParameterAnnotation(i + start, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, parameterDescriptor.getName()); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, parameterDescriptor.getName()); if(parameterDescriptor.hasDefaultValue()) { - av.visit(StdlibNames.JET_PARAMETER_HAS_DEFAULT_VALUE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD, true); } if(parameterDescriptor.getOutType().isNullable()) { - av.visit(StdlibNames.JET_PARAMETER_NULLABLE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } av.visitEnd(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 312f297acc6..421ad544fe4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -6,6 +6,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.OverridingUtil; +import org.jetbrains.jet.lang.resolve.java.StdlibNames; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; @@ -16,9 +17,6 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; -import org.objectweb.asm.util.CheckSignatureAdapter; import java.util.*; @@ -29,7 +27,9 @@ import java.util.*; */ public class ImplementationBodyCodegen extends ClassBodyCodegen { private JetDelegationSpecifier superCall; - private String superClass = "java/lang/Object"; + private String superClass; + @Nullable // null means java/lang/Object + private JetType superClassType; private final JetTypeMapper typeMapper; private final BindingContext bindingContext; @@ -39,28 +39,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { bindingContext = state.getBindingContext(); } - private Set getSuperInterfaces(JetClassOrObject aClass) { - List delegationSpecifiers = aClass.getDelegationSpecifiers(); - Set superInterfaces = new LinkedHashSet(); - - for (JetDelegationSpecifier specifier : delegationSpecifiers) { - JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); - assert superType != null; - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - if(CodegenUtil.isInterface(superClassDescriptor)) { - superInterfaces.add(typeMapper.getFQName(superClassDescriptor)); - } - } - return superInterfaces; - } - @Override protected void generateDeclaration() { getSuperClass(); - List interfaces = new ArrayList(); - interfaces.add("jet/JetObject"); - interfaces.addAll(getSuperInterfaces(myClass)); + JvmClassSignature signature = signature(); boolean isAbstract = false; boolean isInterface = false; @@ -77,10 +60,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0) | (isInterface ? Opcodes.ACC_INTERFACE : 0/*Opcodes.ACC_SUPER*/), - jvmName(), - genericSignature(), - superClass, - interfaces.toArray(new String[interfaces.size()]) + signature.getName(), + signature.getGenericSignature(), + signature.getSuperclassName(), + signature.getInterfaces().toArray(new String[0]) ); v.visitSource(myClass.getContainingFile().getName(), null); @@ -94,30 +77,57 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { annotationVisitor.visitEnd(); } } + + private JvmClassSignature signature() { + String genericSignature; + List superInterfaces; - @Nullable - private String genericSignature() { - List typeParameters = descriptor.getTypeConstructor().getParameters(); - - SignatureWriter signatureWriter = new SignatureWriter(); - SignatureVisitor signatureVisitor = JetTypeMapper.DEBUG_SIGNATURE_WRITER - ? new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, signatureWriter) - : signatureWriter; - for (TypeParameterDescriptor typeParameter : typeParameters) { - signatureVisitor.visitFormalTypeParameter(typeParameter.getName()); - SignatureVisitor classBoundVisitor = signatureVisitor.visitClassBound(); - // TODO: wrong - JetTypeMapper.visitAsmType(classBoundVisitor, JetTypeMapper.TYPE_OBJECT); + { + LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); + + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + + + { // type parameters + List typeParameters = descriptor.getTypeConstructor().getParameters(); + typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); + } + + + { // superclass + signatureVisitor.writeSuperclass(); + if (superClassType == null) { + signatureVisitor.writeClassBegin(superClass); + signatureVisitor.writeClassEnd(); + } else { + typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + } + signatureVisitor.writeSuperclassEnd(); + } + + + { // superinterfaces + superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.isInterface(superClassDescriptor)) { + signatureVisitor.writeInterface(); + Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + signatureVisitor.writeInterfaceEnd(); + superInterfacesLinkedHashSet.add(jvmName.getInternalName()); + } + } + + superInterfaces = new ArrayList(superInterfacesLinkedHashSet); + } + + // TODO: null if class is not generic and does not have generic superclasses + genericSignature = signatureVisitor.makeJavaString(); } - SignatureVisitor superclassSignatureVisitor = signatureVisitor.visitSuperclass(); - // TODO: wrong - superclassSignatureVisitor.visitClassType("java/lang/Object"); - // TODO: add interfaces - superclassSignatureVisitor.visitEnd(); - - // TODO: return null if class is not generic and does not have generic superclasses - - return signatureWriter.toString(); + return new JvmClassSignature(jvmName(), superClass, superInterfaces, genericSignature); } private String jvmName() { @@ -125,6 +135,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } protected void getSuperClass() { + superClass = "java/lang/Object"; + superClassType = null; + List delegationSpecifiers = myClass.getDelegationSpecifiers(); if(myClass instanceof JetClass && ((JetClass) myClass).isTrait()) @@ -136,6 +149,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { assert superType != null; ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); if(!CodegenUtil.isInterface(superClassDescriptor)) { + superClassType = superType; superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), kind).getInternalName(); superCall = specifier; } @@ -305,8 +319,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { parameterTypes.add(typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); } - List typeParameters = descriptor.getTypeConstructor().getParameters(); - for (int n = typeParameters.size(); n > 0; n--) { + if (CodegenUtil.requireTypeInfoConstructorArg(descriptor.getDefaultType())) { parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); } @@ -365,12 +378,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state); - for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) { - if(constructorDescriptor != null) - codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); - else - codegen.addTypeParameter(descriptor.getTypeConstructor().getParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); - } +// for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) { +// if(constructorDescriptor != null) +// codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); +// else +// codegen.addTypeParameter(descriptor.getTypeConstructor().getParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); +// } String classname = typeMapper.mapType(descriptor.getDefaultType(), kind).getInternalName(); final Type classType = Type.getType("L" + classname + ";"); @@ -399,7 +412,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { parameterTypes.add(typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); } for(TypeProjection typeParameterDescriptor : superType.getArguments()) { - codegen.generateTypeInfo(typeParameterDescriptor.getType()); + codegen.generateTypeInfo(typeParameterDescriptor.getType(), null); parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); } Method superCallMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); @@ -447,10 +460,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(0, classType); iv.load(frameMap.getOuterThisIndex(), type); iv.putfield(classname, fieldName, interfaceDesc); + + Type outerType = typeMapper.mapType(outerDescriptor.getDefaultType()); + MethodVisitor outer = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getOuterObject", "()Ljet/JetObject;", null, null); + outer.visitCode(); + outer.visitVarInsn(Opcodes.ALOAD, 0); + outer.visitFieldInsn(Opcodes.GETFIELD, classname, "this$0", outerType.getDescriptor()); + outer.visitInsn(Opcodes.ARETURN); + outer.visitMaxs(0, 0); + outer.visitEnd(); } - if (CodegenUtil.hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { - generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv); + if (CodegenUtil.requireTypeInfoConstructorArg(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { + iv.load(0, JetTypeMapper.TYPE_OBJECT); + iv.load(frameMap.getTypeInfoIndex(), JetTypeMapper.TYPE_OBJECT); + iv.invokevirtual(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V"); } if(closure != null) { @@ -691,46 +715,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - protected void generateTypeInfoInitializer(int firstTypeParameter, int typeParamCount, InstructionAdapter iv) { - iv.load(0, JetTypeMapper.TYPE_OBJECT); - - iv.aconst(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION)); - iv.iconst(0); - - if(CodegenUtil.hasOuterTypeInfo(descriptor)) { - iv.load(1, JetTypeMapper.TYPE_OBJECT); - iv.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); - } - - if(typeParamCount != 0) { - iv.iconst(typeParamCount); - iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION); - - for (int i = 0; i < typeParamCount; i++) { - iv.dup(); - iv.iconst(i); - iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); - iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION); - iv.astore(JetTypeMapper.TYPE_OBJECT); - } - - if(CodegenUtil.hasOuterTypeInfo(descriptor)) { - iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); - } - else - iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); - } - else { - if(CodegenUtil.hasOuterTypeInfo(descriptor)) { - iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;"); - } - else - iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); - } - - iv.invokevirtual(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V"); - } - protected void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) { for (JetDeclaration declaration : myClass.getDeclarations()) { if (declaration instanceof JetProperty) { @@ -827,15 +811,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; JetType defaultType = descriptor.getDefaultType(); - if(CodegenUtil.hasTypeInfoField(defaultType)) { - if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) { + if(CodegenUtil.requireTypeInfoConstructorArg(defaultType)) { + if(!CodegenUtil.hasDerivedTypeInfoField(defaultType)) { v.newField(myClass, Opcodes.ACC_PROTECTED, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); - InstructionAdapter iv = null; if (v.generateCode()) { mv.visitCode(); - iv = new InstructionAdapter(mv); + InstructionAdapter iv = new InstructionAdapter(mv); String owner = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(); iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.getfield(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); @@ -847,7 +830,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv = v.newMethod(myClass, Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V", null, null); if (v.generateCode()) { mv.visitCode(); - iv = new InstructionAdapter(mv); + InstructionAdapter iv = new InstructionAdapter(mv); String owner = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(); iv.load(0, JetTypeMapper.TYPE_OBJECT); iv.load(1, JetTypeMapper.TYPE_OBJECT); @@ -884,14 +867,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { public void generate(InstructionAdapter v) { v.aconst(typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION)); v.iconst(0); - ClassDescriptor outerClassDescriptor = CodegenUtil.getOuterClassDescriptor(descriptor); - if(outerClassDescriptor == null || CodegenUtil.isClassObject(descriptor)) { - v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); - } - else { - v.getstatic(typeMapper.mapType(outerClassDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); - v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;"); - } + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); v.putstatic(typeMapper.mapType(descriptor.getDefaultType(), kind).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); } }); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 06b23293f82..d09e0480f0b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -18,9 +18,6 @@ import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; -import org.objectweb.asm.util.CheckSignatureAdapter; import java.util.*; @@ -57,6 +54,9 @@ public class JetTypeMapper { public static final Type ARRAY_DOUBLE_TYPE = Type.getType(double[].class); public static final Type ARRAY_BOOL_TYPE = Type.getType(boolean[].class); public static final Type ARRAY_GENERIC_TYPE = Type.getType(Object[].class); + public static final Type JET_PARAMETER_TYPE = Type.getObjectType("jet/typeinfo/JetValueParameter"); + public static final Type JET_TYPE_PARAMETER_TYPE = Type.getObjectType("jet/typeinfo/JetTypeParameter"); + public static final Type JET_METHOD_TYPE = Type.getObjectType("jet/typeinfo/JetMethod"); private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; @@ -86,7 +86,11 @@ 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 JetStandardLibrary getStandardLibrary() { + return standardLibrary; + } + public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; this.bindingContext = bindingContext; @@ -158,10 +162,10 @@ public class JetTypeMapper { return mapReturnType(jetType, null); } - @NotNull private Type mapReturnType(final JetType jetType, @Nullable SignatureVisitor signatureVisitor) { + @NotNull private Type mapReturnType(final JetType jetType, @Nullable BothSignatureWriter signatureVisitor) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { if (signatureVisitor != null) { - signatureVisitor.visitBaseType('V'); + signatureVisitor.writeAsmType(Type.VOID_TYPE); } return Type.VOID_TYPE; } @@ -219,10 +223,10 @@ public class JetTypeMapper { } @NotNull public Type mapType(final JetType jetType) { - return mapType(jetType, (SignatureVisitor) null); + return mapType(jetType, (BothSignatureWriter) null); } - @NotNull private Type mapType(JetType jetType, @Nullable SignatureVisitor signatureVisitor) { + @NotNull private Type mapType(JetType jetType, @Nullable BothSignatureWriter signatureVisitor) { return mapType(jetType, OwnerKind.IMPLEMENTATION, signatureVisitor); } @@ -230,17 +234,22 @@ public class JetTypeMapper { return mapType(jetType, kind, null); } - @NotNull private Type mapType(JetType jetType, OwnerKind kind, @Nullable SignatureVisitor signatureVisitor) { + @NotNull private Type mapType(JetType jetType, OwnerKind kind, @Nullable BothSignatureWriter signatureVisitor) { return mapType(jetType, kind, signatureVisitor, false); } - @NotNull private Type mapType(JetType jetType, OwnerKind kind, @Nullable SignatureVisitor signatureVisitor, boolean boxPrimitive) { + @NotNull public Type mapType(JetType jetType, OwnerKind kind, @Nullable BothSignatureWriter signatureVisitor, boolean boxPrimitive) { Type known = knowTypes.get(jetType); if (known != null) { return mapKnownAsmType(jetType, known, signatureVisitor, boxPrimitive); } DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); + + if (ErrorUtils.isError(descriptor)) { + throw new IllegalStateException("should not compile an error type"); + } + if (standardLibrary.getArray().equals(descriptor)) { if (jetType.getArguments().size() != 1) { throw new UnsupportedOperationException("arrays must have one type argument"); @@ -248,8 +257,9 @@ public class JetTypeMapper { JetType memberType = jetType.getArguments().get(0).getType(); if (signatureVisitor != null) { - SignatureVisitor arraySignatureVisitor = signatureVisitor.visitArrayType(); - mapType(memberType, kind, arraySignatureVisitor, true); + signatureVisitor.writeArrayType(); + mapType(memberType, kind, signatureVisitor, true); + signatureVisitor.writeArrayEnd(); } if (!isGenericsArray(jetType)) { @@ -272,13 +282,14 @@ public class JetTypeMapper { Type asmType = Type.getObjectType(name + (kind == OwnerKind.TRAIT_IMPL ? "$$TImpl" : "")); if (signatureVisitor != null) { - signatureVisitor.visitClassType(asmType.getInternalName()); + signatureVisitor.writeClassBegin(asmType.getInternalName()); for (TypeProjection proj : jetType.getArguments()) { // TODO: +- - SignatureVisitor argumentSignatureVisitor = signatureVisitor.visitTypeArgument('='); - mapType(proj.getType(), kind, argumentSignatureVisitor, true); + signatureVisitor.writeTypeArgument('='); + mapType(proj.getType(), kind, signatureVisitor, true); + signatureVisitor.writeTypeArgumentEnd(); } - signatureVisitor.visitEnd(); + signatureVisitor.writeClassEnd(); } return asmType; @@ -287,7 +298,7 @@ public class JetTypeMapper { if (descriptor instanceof TypeParameterDescriptor) { if (signatureVisitor != null) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) jetType.getConstructor().getDeclarationDescriptor(); - signatureVisitor.visitTypeVariable(typeParameterDescriptor.getName()); + signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName()); } return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); @@ -296,7 +307,7 @@ public class JetTypeMapper { throw new UnsupportedOperationException("Unknown type " + jetType); } - private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable SignatureVisitor signatureVisitor, boolean genericTypeParameter) { + private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor, boolean genericTypeParameter) { if (signatureVisitor != null) { if (genericTypeParameter) { visitAsmType(signatureVisitor, boxType(asmType)); @@ -307,23 +318,8 @@ public class JetTypeMapper { return asmType; } - public static void visitAsmType(SignatureVisitor visitor, Type asmType) { - switch (asmType.getSort()) { - case Type.OBJECT: - visitor.visitClassType(asmType.getInternalName()); - visitor.visitEnd(); - return; - case Type.ARRAY: - SignatureVisitor elementSignatureVisitor = visitor.visitArrayType(); - visitAsmType(elementSignatureVisitor, asmType.getElementType()); - return; - default: - String descriptor = asmType.getDescriptor(); - if (descriptor.length() != 1) { - throw new IllegalStateException(); - } - visitor.visitBaseType(descriptor.charAt(0)); - } + public static void visitAsmType(BothSignatureWriter visitor, Type asmType) { + visitor.writeAsmType(asmType); } public static Type unboxType(final Type type) { @@ -379,8 +375,6 @@ public class JetTypeMapper { return asmType; } - public static final boolean DEBUG_SIGNATURE_WRITER = true; - public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, boolean superCall, OwnerKind kind) { if(functionDescriptor == null) return null; @@ -444,22 +438,12 @@ public class JetTypeMapper { needGenericSignature = false; } - SignatureWriter signatureWriter = null; - SignatureVisitor signatureVisitor = null; + BothSignatureWriter signatureVisitor = null; if (needGenericSignature) { - signatureWriter = new SignatureWriter(); - signatureVisitor = DEBUG_SIGNATURE_WRITER ? new CheckSignatureAdapter(CheckSignatureAdapter.METHOD_SIGNATURE, signatureWriter) : signatureWriter; + signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); } - for (TypeParameterDescriptor typeParameterDescriptor : f.getTypeParameters()) { - if (signatureVisitor != null) { - signatureVisitor.visitFormalTypeParameter(typeParameterDescriptor.getName()); - SignatureVisitor classBoundVisitor = signatureVisitor.visitClassBound(); - // TODO: wrong base - visitAsmType(classBoundVisitor, TYPE_OBJECT); - // TODO: interfaces - } - } + writeFormalTypeParameters(f.getTypeParameters(), signatureVisitor); final ReceiverDescriptor receiverTypeRef = f.getReceiverParameter(); final JetType receiverType = !receiverTypeRef.exists() ? null : receiverTypeRef.getType(); @@ -477,24 +461,98 @@ public class JetTypeMapper { parameterTypes.add(type); } if (receiverType != null) { - parameterTypes.add(mapType(receiverType, signatureVisitor != null ? signatureVisitor.visitParameterType() : null)); + if (signatureVisitor != null) { + signatureVisitor.writeParameterType(); + } + parameterTypes.add(mapType(receiverType, signatureVisitor)); + if (signatureVisitor != null) { + signatureVisitor.writeParameterTypeEnd(); + } } for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { parameterTypes.add(TYPE_TYPEINFO); if (signatureVisitor != null) { - visitAsmType(signatureVisitor.visitParameterType(), TYPE_TYPEINFO); + signatureVisitor.writeParameterType(); + visitAsmType(signatureVisitor, TYPE_TYPEINFO); + signatureVisitor.writeParameterTypeEnd(); } } } for (ValueParameterDescriptor parameter : parameters) { - Type type = mapType(parameter.getOutType(), signatureVisitor != null ? signatureVisitor.visitParameterType() : null); + if (signatureVisitor != null) { + signatureVisitor.writeParameterType(); + } + Type type = mapType(parameter.getOutType(), signatureVisitor); + if (signatureVisitor != null) { + signatureVisitor.writeParameterTypeEnd(); + } valueParameterTypes.add(type); parameterTypes.add(type); } - Type returnType = f instanceof ConstructorDescriptor ? Type.VOID_TYPE : mapReturnType(f.getReturnType(), signatureVisitor != null ? signatureVisitor.visitReturnType() : null); + Type returnType; + if (f instanceof ConstructorDescriptor) { + returnType = Type.VOID_TYPE; + if (signatureVisitor != null) { + signatureVisitor.writeReturnType(); + visitAsmType(signatureVisitor, Type.VOID_TYPE); + signatureVisitor.writeReturnTypeEnd(); + } + } else { + if (signatureVisitor != null) { + signatureVisitor.writeReturnType(); + returnType = mapReturnType(f.getReturnType(), signatureVisitor); + signatureVisitor.writeReturnTypeEnd(); + } + else { + returnType = mapReturnType(f.getReturnType(), null); + } + } Method method = new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, signatureWriter != null ? signatureWriter.toString() : null); + return new JvmMethodSignature(method, signatureVisitor != null ? signatureVisitor.makeJavaString() : null); + } + + + public void writeFormalTypeParameters(List typeParameters, BothSignatureWriter signatureVisitor) { + if (signatureVisitor == null) { + return; + } + + for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); + } + } + + private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) { + signatureVisitor.writeFormalTypeParameter(typeParameterDescriptor.getName()); + + classBound: + { + signatureVisitor.writeClassBound(); + + for (JetType jetType : typeParameterDescriptor.getUpperBounds()) { + if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) { + if (!CodegenUtil.isInterface(jetType)) { + mapType(jetType, signatureVisitor); + break classBound; + } + } + } + + // "extends Object" seems to be not optional according to ClassFileFormat-Java5.pdf + } + signatureVisitor.writeClassBoundEnd(); + + for (JetType jetType : typeParameterDescriptor.getUpperBounds()) { + if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) { + if (CodegenUtil.isInterface(jetType)) { + signatureVisitor.writeInterfaceBound(); + mapType(jetType, signatureVisitor); + signatureVisitor.writeInterfaceBoundEnd(); + } + } + } + } public JvmMethodSignature mapSignature(String name, FunctionDescriptor f) { @@ -575,10 +633,8 @@ public class JetTypeMapper { parameterTypes.add(mapType(CodegenUtil.getOuterClassDescriptor(classDescriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); } - List typeParameters = classDescriptor.getTypeConstructor().getParameters(); - for (TypeParameterDescriptor typeParameter : typeParameters) { - if(typeParameter.isReified()) - parameterTypes.add(TYPE_TYPEINFO); + if (CodegenUtil.requireTypeInfoConstructorArg(classDescriptor.getDefaultType())) { + parameterTypes.add(TYPE_TYPEINFO); } for (ValueParameterDescriptor parameter : parameters) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java new file mode 100644 index 00000000000..e866f873f8a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java @@ -0,0 +1,36 @@ +package org.jetbrains.jet.codegen; + +import java.util.List; + +/** + * @author Stepan Koltsov + */ +public class JvmClassSignature { + private final String name; + private final String superclassName; + private final List interfaces; + private final String genericSignature; + + public JvmClassSignature(String name, String superclassName, List interfaces, String genericSignature) { + this.name = name; + this.superclassName = superclassName; + this.interfaces = interfaces; + this.genericSignature = genericSignature; + } + + public String getName() { + return name; + } + + public String getSuperclassName() { + return superclassName; + } + + public List getInterfaces() { + return interfaces; + } + + public String getGenericSignature() { + return genericSignature; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 837c1503717..5e8b92a7849 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -2,10 +2,12 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiFile; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; +import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.TypeUtils; @@ -42,7 +44,8 @@ public class NamespaceCodegen { } public void generate(JetNamespace namespace) { - final CodegenContext context = CodegenContext.STATIC.intoNamespace(state.getBindingContext().get(BindingContext.NAMESPACE, namespace)); + NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.NAMESPACE, namespace); + final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); final FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state); @@ -145,7 +148,7 @@ public class NamespaceCodegen { } DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor(); - if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) { + if(!jetType.equals(root) && jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor) && !JetStandardClasses.getAny().equals(declarationDescriptor)) { // TODO: we need some better checks here v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); return; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index d8591fe5e4a..f9167601b55 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -629,7 +630,7 @@ public abstract class StackValue { for (TypeParameterDescriptor typeParameterDescriptor : setterDescriptor.getOriginal().getTypeParameters()) { if(typeParameterDescriptor.isReified()) { - codegen.generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor)); + codegen.generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor), null); } } @@ -1010,7 +1011,8 @@ public abstract class StackValue { return codegen.typeMapper.mapType(callableMethod.getReceiverClass()); } else { - return codegen.typeMapper.mapType(callableMethod.getThisType()); + JetType thisType = callableMethod.getThisType(); + return codegen.typeMapper.mapType(thisType); } } else { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java index 4c0f906e5ab..8fcd6d57500 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArrayIterator.java @@ -5,14 +5,12 @@ import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.JetCallExpression; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetStandardLibrary; -import org.jetbrains.jet.lang.types.JetType; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -30,7 +28,7 @@ public class ArrayIterator implements IntrinsicMethod { ClassDescriptor containingDeclaration = (ClassDescriptor) funDescriptor.getContainingDeclaration().getOriginal(); JetStandardLibrary standardLibrary = codegen.getState().getStandardLibrary(); if(containingDeclaration.equals(standardLibrary.getArray())) { - codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType()); + codegen.generateTypeInfo(funDescriptor.getReturnType().getArguments().get(0).getType(), null); v.invokestatic("jet/runtime/ArrayIterator", "iterator", "([Ljava/lang/Object;Ljet/typeinfo/TypeInfo;)Ljet/Iterator;"); return StackValue.onStack(JetTypeMapper.TYPE_ITERATOR); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java index 3c9c43d97f7..73a23e605e8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ValueTypeInfo.java @@ -17,7 +17,7 @@ public class ValueTypeInfo implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { codegen.gen(arguments.get(0), JetTypeMapper.TYPE_JET_OBJECT); - v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); + v.invokeinterface(JetTypeMapper.TYPE_JET_OBJECT.getInternalName(), "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); return StackValue.onStack(JetTypeMapper.TYPE_TYPEINFO); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java new file mode 100644 index 00000000000..6485efde6bf --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java @@ -0,0 +1,161 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureReader + */ +public class JetSignatureReader { + + private final String signature; + + public JetSignatureReader(String signature) { + this.signature = signature; + } + + + public void accept(final JetSignatureVisitor v) { + String signature = this.signature; + int len = signature.length(); + int pos; + char c; + + if (signature.charAt(0) == '<') { + pos = 2; + do { + int end = signature.indexOf(':', pos); + v.visitFormalTypeParameter(signature.substring(pos - 1, end)); + pos = end + 1; + + c = signature.charAt(pos); + if (c == 'L' || c == '[' || c == 'T') { + pos = parseType(signature, pos, v.visitClassBound()); + } + + while ((c = signature.charAt(pos++)) == ':') { + pos = parseType(signature, pos, v.visitInterfaceBound()); + } + } while (c != '>'); + } else { + pos = 0; + } + + if (signature.charAt(pos) == '(') { + pos++; + while (signature.charAt(pos) != ')') { + pos = parseType(signature, pos, v.visitParameterType()); + } + pos = parseType(signature, pos + 1, v.visitReturnType()); + while (pos < len) { + pos = parseType(signature, pos + 1, v.visitExceptionType()); + } + } else { + pos = parseType(signature, pos, v.visitSuperclass()); + while (pos < len) { + pos = parseType(signature, pos, v.visitInterface()); + } + } + } + + + private static int parseType( + final String signature, + int pos, + final JetSignatureVisitor v) + { + char c; + int start, end; + boolean visited, inner; + String name; + + boolean nullable = false; + if (signature.charAt(pos) == '?') { + nullable = true; + pos++; + } + + switch (c = signature.charAt(pos++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'V': + v.visitBaseType(c, nullable); + return pos; + + case '[': + return parseType(signature, pos, v.visitArrayType(nullable)); + + case 'T': + end = signature.indexOf(';', pos); + v.visitTypeVariable(signature.substring(pos, end), nullable); + return end + 1; + + default: // case 'L': + start = pos; + visited = false; + inner = false; + for (;;) { + switch (c = signature.charAt(pos++)) { + case '.': + case ';': + if (!visited) { + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + } + if (c == ';') { + v.visitEnd(); + return pos; + } + start = pos; + visited = false; + inner = true; + break; + + case '<': + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + visited = true; + top: for (;;) { + switch (c = signature.charAt(pos)) { + case '>': + break top; + case '*': + ++pos; + v.visitTypeArgument(); + break; + case '+': + case '-': + pos = parseType(signature, + pos + 1, + v.visitTypeArgument(c)); + break; + default: + pos = parseType(signature, + pos, + v.visitTypeArgument('=')); + break; + } + } + } + } + } + } + + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java new file mode 100644 index 00000000000..04e1319dd03 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java @@ -0,0 +1,141 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureVisitor + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures + */ +public interface JetSignatureVisitor { + + /** + * Wildcard for an "extends" type argument. + */ + char EXTENDS = '+'; + + /** + * Wildcard for a "super" type argument. + */ + char SUPER = '-'; + + /** + * Wildcard for a normal type argument. + */ + char INSTANCEOF = '='; + + /** + * Visits a formal type parameter. + * + * @param name the name of the formal parameter. + */ + void visitFormalTypeParameter(String name); + + /** + * Visits the class bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the class bound. + */ + JetSignatureVisitor visitClassBound(); + + /** + * Visits an interface bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the interface bound. + */ + JetSignatureVisitor visitInterfaceBound(); + + /** + * Visits the type of the super class. + * + * @return a non null visitor to visit the signature of the super class + * type. + */ + JetSignatureVisitor visitSuperclass(); + + /** + * Visits the type of an interface implemented by the class. + * + * @return a non null visitor to visit the signature of the interface type. + */ + JetSignatureVisitor visitInterface(); + + /** + * Visits the type of a method parameter. + * + * @return a non null visitor to visit the signature of the parameter type. + */ + JetSignatureVisitor visitParameterType(); + + /** + * Visits the return type of the method. + * + * @return a non null visitor to visit the signature of the return type. + */ + JetSignatureVisitor visitReturnType(); + + /** + * Visits the type of a method exception. + * + * @return a non null visitor to visit the signature of the exception type. + */ + JetSignatureVisitor visitExceptionType(); + + /** + * Visits a signature corresponding to a primitive type. + * + * @param descriptor the descriptor of the primitive type, or 'V' for + * void. + */ + void visitBaseType(char descriptor, boolean nullable); + + /** + * Visits a signature corresponding to a type variable. + * + * @param name the name of the type variable. + */ + void visitTypeVariable(String name, boolean nullable); + + /** + * Visits a signature corresponding to an array type. + * + * @return a non null visitor to visit the signature of the array element + * type. + */ + JetSignatureVisitor visitArrayType(boolean nullable); + + /** + * Starts the visit of a signature corresponding to a class or interface + * type. + * + * @param name the internal name of the class or interface. + */ + void visitClassType(String name, boolean nullable); + + /** + * Visits an inner class. + * + * @param name the local name of the inner class in its enclosing class. + */ + void visitInnerClassType(String name, boolean nullable); + + /** + * Visits an unbounded type argument of the last visited class or inner + * class type. + */ + void visitTypeArgument(); + + /** + * Visits a type argument of the last visited class or inner class type. + * + * @param wildcard '+', '-' or '='. + * @return a non null visitor to visit the signature of the type argument. + */ + JetSignatureVisitor visitTypeArgument(char wildcard); + + /** + * Ends the visit of a signature corresponding to a class or interface type. + */ + void visitEnd(); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java new file mode 100644 index 00000000000..b85d48b3ecc --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java @@ -0,0 +1,201 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureWriter; + +/** + * @author Stepan Koltsov + * + * @see SignatureWriter + */ +public class JetSignatureWriter implements JetSignatureVisitor { + + /** + * Buffer used to construct the signature. + */ + private final StringBuffer buf = new StringBuffer(); + + /** + * Indicates if the signature contains formal type parameters. + */ + private boolean hasFormals; + + /** + * Indicates if the signature contains method parameter types. + */ + private boolean hasParameters; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Constructs a new {@link SignatureWriter} object. + */ + public JetSignatureWriter() { + } + + // ------------------------------------------------------------------------ + // Implementation of the SignatureVisitor interface + // ------------------------------------------------------------------------ + + @Override + public void visitFormalTypeParameter(final String name) { + if (!hasFormals) { + hasFormals = true; + buf.append('<'); + } + buf.append(name); + buf.append(':'); + } + + @Override + public JetSignatureWriter visitClassBound() { + return this; + } + + @Override + public JetSignatureWriter visitInterfaceBound() { + buf.append(':'); + return this; + } + + @Override + public JetSignatureWriter visitSuperclass() { + endFormals(); + return this; + } + + @Override + public JetSignatureWriter visitInterface() { + return this; + } + + @Override + public JetSignatureWriter visitParameterType() { + endFormals(); + if (!hasParameters) { + hasParameters = true; + buf.append('('); + } + return this; + } + + @Override + public JetSignatureWriter visitReturnType() { + endFormals(); + if (!hasParameters) { + buf.append('('); + } + buf.append(')'); + return this; + } + + @Override + public JetSignatureWriter visitExceptionType() { + buf.append('^'); + return this; + } + + private void visitNullabe(boolean nullable) { + if (nullable) { + buf.append('?'); + } + } + + @Override + public void visitBaseType(final char descriptor, boolean nullable) { + visitNullabe(nullable); + buf.append(descriptor); + } + + @Override + public void visitTypeVariable(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('T'); + buf.append(name); + buf.append(';'); + } + + @Override + public JetSignatureWriter visitArrayType(boolean nullable) { + visitNullabe(nullable); + buf.append('['); + return this; + } + + @Override + public void visitClassType(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('L'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitInnerClassType(final String name, boolean nullable) { + endArguments(); + visitNullabe(nullable); + buf.append('.'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + buf.append('*'); + } + + @Override + public JetSignatureWriter visitTypeArgument(final char wildcard) { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + if (wildcard != '=') { + buf.append(wildcard); + } + return this; + } + + @Override + public void visitEnd() { + endArguments(); + buf.append(';'); + } + + public String toString() { + return buf.toString(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Ends the formal type parameters section of the signature. + */ + private void endFormals() { + if (hasFormals) { + hasFormals = false; + buf.append('>'); + } + } + + /** + * Ends the type arguments of a class or inner class type. + */ + private void endArguments() { + if (argumentStack % 2 != 0) { + buf.append('>'); + } + argumentStack /= 2; + } +} 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 cf154895c99..d74c6aafd28 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 @@ -14,7 +14,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.StdlibNames; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.plugin.JetFileType; @@ -370,13 +369,13 @@ public class JavaDescriptorResolver { PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); attributes.toString(); - if (annotation.getQualifiedName().equals(StdlibNames.JET_PARAMETER_CLASS)) { - PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_PARAMETER_NAME_FIELD); + if (annotation.getQualifiedName().equals(StdlibNames.JET_VALUE_PARAMETER_CLASS)) { + PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD); if (nameExpression != null) { name = (String) nameExpression.getValue(); } - PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_PARAMETER_NULLABLE_FIELD); + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD); if (nullableExpression != null) { nullable = (Boolean) nullableExpression.getValue(); } else { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 94240f21b34..098b8ec6bdf 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java @@ -58,7 +58,6 @@ public class JavaPackageScope extends JetScopeImpl { return Collections.emptySet(); } - System.out.println(psiClass.getQualifiedName()); return semanticServices.getDescriptorResolver().resolveFunctionGroup(containingDescriptor, psiClass, null, name, true); // return Collections.emptySet(); } @@ -78,6 +77,7 @@ public class JavaPackageScope extends JetScopeImpl { final PsiPackage javaPackage = semanticServices.getDescriptorResolver().findPackage(packageFQN); if (javaPackage != null) { + boolean isKotlinNamespace = semanticServices.getKotlinNamespaceDescriptor(javaPackage.getQualifiedName()) != null; final JavaDescriptorResolver descriptorResolver = semanticServices.getDescriptorResolver(); for (PsiPackage psiSubPackage : javaPackage.getSubPackages()) { @@ -85,6 +85,8 @@ public class JavaPackageScope extends JetScopeImpl { } for (PsiClass psiClass : javaPackage.getClasses()) { + if (isKotlinNamespace && "namespace".equals(psiClass.getName())) continue; + // If this is a Kotlin class, we have already taken it through a containing namespace descriptor ClassDescriptor kotlinClassDescriptor = semanticServices.getKotlinClassDescriptor(psiClass.getQualifiedName()); if (kotlinClassDescriptor != null) { 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 new file mode 100644 index 00000000000..214be7c888d --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -0,0 +1,36 @@ +package org.jetbrains.jet.lang.resolve.java; + +import org.objectweb.asm.Type; + +/** + * @author Stepan Koltsov + */ +public class StdlibNames { + + public static final String JET_VALUE_PARAMETER_CLASS = "jet.typeinfo.JetValueParameter"; + public static final String JET_VALUE_PARAMETER_DESCRIPTOR = "Ljet/typeinfo/JetValueParameter;"; + + public static final String JET_VALUE_PARAMETER_NAME_FIELD = "name"; + public static final String JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue"; + public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable"; + + + public static final String JET_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter"; + public static final String JET_TYPE_PARAMETER_DESCRIPTOR = "Ljet/typeinfo/JetTypeParameter;"; + + public static final String JET_TYPE_PARAMETER_NAME_FIELD = "name"; + + + public static final String JET_METHOD_CLASS = "jet.typeinfo.JetMethod"; + public static final String JET_METHOD_DESCRIPTOR = "Ljet/typeinfo/JetMethod;"; + + public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; + + + public static final String JET_OBJECT_INTERNAL = "jet/JetObject"; + public static final String JET_OBJECT_CLASS = "jet.JetObject"; + public static final String JET_OBJECT_DESCRIPTOR = "Ljet/JetObject;"; + + private StdlibNames() { + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 2a7c167d0fb..47cdc05dfdf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -131,11 +131,15 @@ public class JetPsiUtil { public static String getFQName(JetClass jetClass) { JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(jetClass, JetNamespace.class, JetClass.class); if (parent instanceof JetNamespace) { - return getFQName(((JetNamespace) parent)) + "." + jetClass.getName(); + return makeFQName(getFQName(((JetNamespace) parent)), jetClass); } if (parent instanceof JetClass) { - return getFQName(((JetClass) parent)) + "." + jetClass.getName(); + return makeFQName(getFQName(((JetClass) parent)), jetClass); } return jetClass.getName(); } + + private static String makeFQName(String prefix, JetClass jetClass) { + return (prefix.length() == 0 ? "" : prefix + ".") + jetClass.getName(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java deleted file mode 100644 index fcc779f5c99..00000000000 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.jetbrains.jet.lang.resolve; - -import org.objectweb.asm.Type; - -/** - * @author Stepan Koltsov - */ -public class StdlibNames { - - public static final Type JET_PARAMETER_TYPE = Type.getObjectType("jet/typeinfo/JetParameter"); - public static final String JET_PARAMETER_CLASS = "jet.typeinfo.JetParameter"; - public static final String JET_PARAMETER_DESCRIPTOR = "Ljet/typeinfo/JetParameter;"; - - public static final String JET_PARAMETER_NAME_FIELD = "name"; - public static final String JET_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue"; - public static final String JET_PARAMETER_NULLABLE_FIELD = "nullable"; - - - public static final Type JET_TYPE_PARAMETER_TYPE = Type.getObjectType("jet/typeinfo/JetTypeParameter"); - public static final String JET_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter"; - public static final String JET_TYPE_PARAMETER_DESCRIPTOR = "Ljet/typeinfo/JetTypeParameter;"; - - public static final String JET_TYPE_PARAMETER_NAME_FIELD = "name"; - - - public static final Type JET_METHOD_TYPE = Type.getObjectType("jet/typeinfo/JetMethod"); - public static final String JET_METHOD_CLASS = "jet.typeinfo.JetMethod"; - public static final String JET_METHOD_DESCRIPTOR = "Ljet/typeinfo/JetMethod;"; - - public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; - -} 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 464445d0009..b5d04a21d8e 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 @@ -29,6 +29,9 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.EXPECTED_TYPE; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.VALUE_ARGUMENT; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; @@ -470,7 +473,7 @@ public class CallResolver { ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, traceForUnknown); JetType type = temporaryServices.getType(scope, expression, substituteDontCare.substitute(valueParameterDescriptor.getOutType(), Variance.INVARIANT)); if (type != null) { - constraintSystem.addSubtypingConstraint(type, effectiveExpectedType); + constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType)); } else { candidateCall.argumentHasNoType(); @@ -483,12 +486,12 @@ public class CallResolver { ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument(); ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter(); if (receiverArgument.exists() && receiverParameter.exists()) { - constraintSystem.addSubtypingConstraint(receiverArgument.getType(), receiverParameter.getType()); + constraintSystem.addSubtypingConstraint(RECEIVER.assertSubtyping(receiverArgument.getType(), receiverParameter.getType())); } // Return type if (expectedType != NO_EXPECTED_TYPE) { - constraintSystem.addSubtypingConstraint(candidateWithFreshVariables.getReturnType(), expectedType); + constraintSystem.addSubtypingConstraint(EXPECTED_TYPE.assertSubtyping(candidateWithFreshVariables.getReturnType(), expectedType)); } // Solution diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java index 59968bae9a4..d254ac771e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionDebugInfo.java @@ -5,7 +5,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; +import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.util.slicedmap.*; @@ -22,8 +22,8 @@ public class ResolutionDebugInfo { public static final WritableSlice> RESULT = Slices.createSimpleSlice(); public static final WritableSlice ERRORS = Slices.createSimpleSlice(); public static final WritableSlice LOG = Slices.createSimpleSlice(); - public static final WritableSlice> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice(); - public static final WritableSlice> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice(); + public static final WritableSlice> BOUNDS_FOR_UNKNOWNS = Slices.createSimpleSlice(); + public static final WritableSlice> BOUNDS_FOR_KNOWNS = Slices.createSimpleSlice(); public static final WritableSlice SOLUTION = Slices.createSimpleSlice(); public static final WritableSlice> UNKNOWNS = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java index 521e7063eba..f5545f22ddb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -13,11 +13,11 @@ import java.util.Map; * @author abreslav */ public interface ResolvedCall { - /** A target callable descriptor as it was accessible in the corresponding scope, i.e. with type parameters not substituted */ + /** A target callable descriptor as it was accessible in the corresponding scope, i.e. with type arguments not substituted */ @NotNull D getCandidateDescriptor(); - /** Type parameters are substituted */ + /** Type arguments are substituted. This descriptor is guaranteed to have NO declared type parameters */ @NotNull D getResultingDescriptor(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/BoundsOwner.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/BoundsOwner.java new file mode 100644 index 00000000000..512b1437d77 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/BoundsOwner.java @@ -0,0 +1,16 @@ +package org.jetbrains.jet.lang.resolve.calls.inference; + +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * @author abreslav + */ +public interface BoundsOwner { + @NotNull + Set getUpperBounds(); + + @NotNull + Set getLowerBounds(); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintResolutionListener.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintResolutionListener.java index 6cbf129fb73..eda1db1082d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintResolutionListener.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintResolutionListener.java @@ -12,11 +12,11 @@ public interface ConstraintResolutionListener { public static final ConstraintResolutionListener DO_NOTHING = new ConstraintResolutionListener() { @Override - public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) { } @Override - public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForKnownType(JetType type, BoundsOwner typeValue) { } @Override @@ -24,18 +24,18 @@ public interface ConstraintResolutionListener { } @Override - public void log(Object message) { + public void log(Object... messageFragments) { } @Override - public void error(Object message) { + public void error(Object... messageFragments) { } }; - void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue); - void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue); + void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue); + void constraintsForKnownType(JetType type, BoundsOwner typeValue); void done(ConstraintSystemSolution solution, Set typeParameterDescriptors); - void log(Object message); - void error(Object message); + void log(Object... messageFragments); + void error(Object... messageFragments); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystem.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystem.java index 8511fb78b37..e071e19bef5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystem.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystem.java @@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.resolve.calls.inference; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; -import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.Variance; /** @@ -11,7 +10,7 @@ import org.jetbrains.jet.lang.types.Variance; public interface ConstraintSystem { void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance); - void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper); + void addSubtypingConstraint(@NotNull SubtypingConstraint constraint); @NotNull ConstraintSystemSolution solve(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java index 8ea8f233b0c..cb68fc94d2c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemImpl.java @@ -143,7 +143,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { } } - listener.log("minimal solution from lowerbounds for " + this + " is " + commonSupertype); + listener.log("minimal solution from lowerbounds for ", this, " is ", commonSupertype); value = new KnownType(commonSupertype); } else { @@ -247,10 +247,10 @@ public class ConstraintSystemImpl implements ConstraintSystem { } @Override - public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure); if (!result) { - listener.error("-- Failed to equate " + a + " and " + b); + listener.error("-- Failed to equate ", a, " and ", b); } return result; } @@ -259,16 +259,16 @@ public class ConstraintSystemImpl implements ConstraintSystem { public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { boolean result = delegate.assertEqualTypeConstructors(a, b); if (!result) { - listener.error("-- Type constructors are not equal: " + a + " and " + b); + listener.error("-- Type constructors are not equal: ", a, " and ", b); } return result; } @Override - public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) { boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure); if (!result) { - listener.error("-- " + subtype + " can't be a subtype of " + supertype); + listener.error("-- ", subtype, " can't be a subtype of ", supertype); } return result; } @@ -277,7 +277,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { boolean result = delegate.noCorrespondingSupertype(subtype, supertype); if (!result) { - listener.error("-- " + subtype + " has no supertype corresponding to " + supertype); + listener.error("-- ", subtype, " has no supertype corresponding to ", supertype); } return result; } @@ -294,7 +294,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { private TypeCheckingProcedure createConstraintExpander() { return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() { @Override - public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { TypeValue aValue = getTypeValueFor(a); TypeValue bValue = getTypeValueFor(b); @@ -309,7 +309,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { } @Override - public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) { TypeValue subtypeValue = getTypeValueFor(subtype); TypeValue supertypeValue = getTypeValueFor(supertype); @@ -382,14 +382,14 @@ public class ConstraintSystemImpl implements ConstraintSystem { } @Override - public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) { - TypeValue typeValueForLower = getTypeValueFor(lower); - TypeValue typeValueForUpper = getTypeValueFor(upper); + public void addSubtypingConstraint(@NotNull SubtypingConstraint constraint) { + TypeValue typeValueForLower = getTypeValueFor(constraint.getSubtype()); + TypeValue typeValueForUpper = getTypeValueFor(constraint.getSupertype()); addSubtypingConstraintOnTypeValues(typeValueForLower, typeValueForUpper); } private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) { - listener.log("Constraint added: " + typeValueForLower + " :< " + typeValueForUpper); + listener.log("Constraint added: ", typeValueForLower, " :< ", typeValueForUpper); if (typeValueForLower != typeValueForUpper) { typeValueForLower.addUpperBound(typeValueForUpper); typeValueForUpper.addLowerBound(typeValueForLower); @@ -409,14 +409,22 @@ public class ConstraintSystemImpl implements ConstraintSystem { KnownType knownBoundType = (KnownType) upperBound; boolean ok = constraintExpander.isSubtypeOf(jetType, knownBoundType.getType()); if (!ok) { - listener.error("Error while expanding '" + jetType + " :< " + knownBoundType.getType() + "'"); + listener.error("Error while expanding '", jetType, " :< ", knownBoundType.getType(), "'"); return new Solution().registerError("Mismatch while expanding constraints"); } } } - // Lower bounds? - + for (TypeValue lowerBound : typeValue.getLowerBounds()) { + if (lowerBound instanceof KnownType) { + KnownType knownBoundType = (KnownType) lowerBound; + boolean ok = constraintExpander.isSubtypeOf(knownBoundType.getType(), jetType); + if (!ok) { + listener.error("Error while expanding '" + knownBoundType.getType() + " :< " + jetType + "'"); + return new Solution().registerError("Mismatch while expanding constraints"); + } + } + } } // Fill in upper bounds from type parameter bounds @@ -435,11 +443,11 @@ public class ConstraintSystemImpl implements ConstraintSystem { } for (UnknownType unknownType : unknownTypes.values()) { - listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType); +// listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType); } for (KnownType knownType : knownTypes.values()) { - listener.constraintsForKnownType(knownType.getType(), knownType); +// listener.constraintsForKnownType(knownType.getType(), knownType); } // Find inconsistencies @@ -469,14 +477,14 @@ public class ConstraintSystemImpl implements ConstraintSystem { JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT); if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType); - listener.error("Constraint violation: " + type + " :< " + boundingType); + listener.error("Constraint violation: ", type, " :< ", boundingType); } } for (TypeValue lowerBound : typeValue.getLowerBounds()) { JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT); if (!typeChecker.isSubtypeOf(boundingType, type)) { solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type); - listener.error("Constraint violation: " + boundingType + " :< " + type); + listener.error("Constraint violation: ", boundingType, " :< ", type); } } } @@ -534,7 +542,7 @@ public class ConstraintSystemImpl implements ConstraintSystem { TypeProjection typeProjection = new TypeProjection(getValue(descriptor)); - listener.log(descriptor + " |-> " + typeProjection); + listener.log(descriptor, " |-> ", typeProjection); return typeProjection; } 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 new file mode 100644 index 00000000000..fd408957971 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintSystemWithPriorities.java @@ -0,0 +1,470 @@ +package org.jetbrains.jet.lang.resolve.calls.inference; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; +import org.jetbrains.jet.lang.types.checker.TypingConstraints; + +import java.util.*; + +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.PARAMETER_BOUND; + +/** + * @author abreslav + */ +public class ConstraintSystemWithPriorities implements ConstraintSystem { + + public static final Comparator SUBTYPING_CONSTRAINT_ORDER = new Comparator() { + @Override + public int compare(SubtypingConstraint o1, SubtypingConstraint o2) { + return o1.getType().compareTo(o2.getType()); + } + }; + + private static class LoopInTypeVariableConstraintsException extends RuntimeException { + public LoopInTypeVariableConstraintsException() {} + } + + //========================================================================================================================================================== + + private final Map knownTypes = Maps.newLinkedHashMap(); // linked - for easier debugging + private final Map unknownTypes = Maps.newLinkedHashMap(); // linked - for easier debugging + private final Set unsolvedUnknowns = Sets.newLinkedHashSet(); // linked - for easier debugging + private final PriorityQueue constraintQueue = new PriorityQueue(10, SUBTYPING_CONSTRAINT_ORDER); + + private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + private final TypeCheckingProcedure constraintExpander; + private final ConstraintResolutionListener listener; + + public ConstraintSystemWithPriorities(ConstraintResolutionListener listener) { + this.listener = listener; + this.constraintExpander = createConstraintExpander(); + } + + @NotNull + private TypeValue getTypeValueFor(@NotNull JetType type) { + DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; + // Checking that this is not a T?, but exactly T + if (typeParameterDescriptor.getDefaultType().isNullable() == type.isNullable()) { + TypeValue unknownType = unknownTypes.get(typeParameterDescriptor); + if (unknownType != null) { + return unknownType; + } + } + } + + TypeValue typeValue = knownTypes.get(type); + if (typeValue == null) { + typeValue = new TypeValue(type); + knownTypes.put(type, typeValue); + } + return typeValue; + } + + @Override + public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { + assert !unknownTypes.containsKey(typeParameterDescriptor); + TypeValue typeValue = new TypeValue(typeParameterDescriptor, positionVariance); + unknownTypes.put(typeParameterDescriptor, typeValue); + unsolvedUnknowns.add(typeValue); + } + + @NotNull + private TypeValue getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) { + TypeValue unknownType = unknownTypes.get(typeParameterDescriptor); + if (unknownType == null) { + throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system: " + typeParameterDescriptor); + } + return unknownType; + } + + @Override + public void addSubtypingConstraint(@NotNull SubtypingConstraint constraint) { + constraintQueue.add(constraint); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Constraint expansion + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private TypeCheckingProcedure createConstraintExpander() { + return new TypeCheckingProcedure(new TypeConstraintBuilderAdapter(new TypingConstraints() { + @Override + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { + TypeValue aValue = getTypeValueFor(a); + TypeValue bValue = getTypeValueFor(b); + + return expandEqualityConstraint(aValue, bValue); + } + + @Override + public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { + return a.equals(b) + || unknownTypes.containsKey(a.getDeclarationDescriptor()) + || unknownTypes.containsKey(b.getDeclarationDescriptor()); + } + + @Override + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) { + TypeValue subtypeValue = getTypeValueFor(subtype); + TypeValue supertypeValue = getTypeValueFor(supertype); + + if (someUnknown(subtypeValue, supertypeValue)) { + expandSubtypingConstraint(subtypeValue, supertypeValue); + } + return true; // For known types further expansion happens automatically + } + + @Override + public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + // If some of the types is an unknown, the constraint must be generated, and we should carry on + // otherwise there can be no solution, and we should fail + TypeValue subTypeValue = getTypeValueFor(subtype); + TypeValue superTypeValue = getTypeValueFor(supertype); + boolean someUnknown = someUnknown(subTypeValue, superTypeValue); + if (someUnknown) { + expandSubtypingConstraint(subTypeValue, superTypeValue); + } + return someUnknown; + } + + private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) { + return !subtypeValue.isKnown() || !supertypeValue.isKnown(); + } + + }, listener)); + } + + private boolean assignValueTo(TypeValue unknown, JetType value) { + if (unknown.hasValue()) { + // If we have already assigned a value to this unknown, + // it is a conflict to assign another one, unless this new one is equal to the previous + return TypeUtils.equalTypes(unknown.getType(), value); + } + unsolvedUnknowns.remove(unknown); + unknown.setValue(value); + return true; + } + + private boolean mergeUnknowns(@NotNull TypeValue a, @NotNull TypeValue b) { + assert !a.isKnown() && !b.isKnown(); + listener.error("!!!mergeUnknowns() is not implemented!!!"); + return false; + } + + public boolean expandEqualityConstraint(TypeValue a, TypeValue b) { + if (a.isKnown() && b.isKnown()) { + return constraintExpander.equalTypes(a.getType(), b.getType()); + } + + // At least one of them is unknown + if (a.isKnown()) { + TypeValue tmp = a; + a = b; + b = tmp; + } + + // Now a is definitely unknown + if (b.isKnown()) { + return assignValueTo(a, b.getType()); + } + + // They are both unknown + return mergeUnknowns(a, b); + } + + private boolean expandSubtypingConstraint(TypeValue lower, TypeValue upper) { + listener.log("Constraint added: ", lower, " :< ", upper); + + if (lower == upper) return true; + + // Remember for a later check + lower.addUpperBound(upper); + upper.addLowerBound(lower); + + if (lower.isKnown() && upper.isKnown()) { + // Two known types: expand constraints + return constraintExpander.isSubtypeOf(lower.getType(), upper.getType()); + } + else if (!lower.isKnown() && !upper.isKnown()) { + // Two unknown types: merge them into one variable + return mergeUnknowns(lower, upper); + } + else { + // One unknown and one known + if (upper.isKnown()) { + if (TypeUtils.canHaveSubtypes(typeChecker, upper.getType())) { + // Upper bound is final -> we have to equate the lower bounds to it + return expandEqualityConstraint(lower, upper); + } + if (lower.getLowerBounds().contains(upper)) { + // upper :< lower :< upper + return expandEqualityConstraint(lower, upper); + } + } + else { + if (upper.getUpperBounds().contains(lower)) { + // lower :< upper :< lower + return expandEqualityConstraint(lower, upper); + } + } + } + return true; + } + + @Override + @NotNull + public ConstraintSystemSolution solve() { + Solution solution = new Solution(); + // At this point we only have type values, no bounds added for them, no values computed for unknown types + + // Generate low-priority constraints from bounds + for (Map.Entry entry : Sets.newHashSet(unknownTypes.entrySet())) { + TypeParameterDescriptor typeParameterDescriptor = entry.getKey(); + TypeValue typeValue = entry.getValue(); + for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) { + addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(typeValue.getOriginalType(), getTypeValueFor(upperBound).getOriginalType())); + } + for (JetType lowerBound : typeParameterDescriptor.getLowerBounds()) { + addSubtypingConstraint(PARAMETER_BOUND.assertSubtyping(getTypeValueFor(lowerBound).getOriginalType(), typeValue.getOriginalType())); + } + } + + // Expand and solve constraints + while (!constraintQueue.isEmpty()) { + SubtypingConstraint constraint = constraintQueue.poll(); + + // Apply constraint + TypeValue lower = getTypeValueFor(constraint.getSubtype()); + TypeValue upper = getTypeValueFor(constraint.getSupertype()); + boolean success = expandSubtypingConstraint(lower, upper); + if (!success) { + solution.registerError(constraint.getErrorMessage()); + break; + } + + // (???) Propagate info + + // Any unknowns left? + if (unsolvedUnknowns.isEmpty()) break; + } + + // Now, let's check the rest of the constraints + + // Expand custom bounds, e.g. List <: List +// for (Map.Entry entry : Sets.newHashSet(knownTypes.entrySet())) { +// JetType jetType = entry.getKey(); +// TypeValue typeValue = entry.getValue(); +// +// for (TypeValue upperBound : typeValue.getUpperBounds()) { +// if (upperBound.isKnown()) { +// boolean ok = constraintExpander.isSubtypeOf(jetType, upperBound.getType()); +// if (!ok) { +// listener.error("Error while expanding '" + jetType + " :< " + upperBound.getType() + "'"); +// return new Solution().registerError("Mismatch while expanding constraints"); +// } +// } +// } +// +// // Lower bounds. Probably not needed for known types, as everything is symmetrical anyway +// } + + // effective bounds for each node +// Set visited = Sets.newHashSet(); +// for (TypeValue unknownType : unknownTypes.values()) { +// transitiveClosure(unknownType, visited); +// } + + for (TypeValue unknownType : unknownTypes.values()) { + listener.constraintsForUnknown(unknownType.getTypeParameterDescriptor(), unknownType); + } + for (TypeValue knownType : knownTypes.values()) { + listener.constraintsForKnownType(knownType.getType(), knownType); + } + + // Find inconsistencies + + // Compute values and check that all bounds are respected by solutions: + // we have set some of them from equality constraints with known types + // and thus the bounds may be violated if some of the constraints conflict + for (TypeValue unknownType : unknownTypes.values()) { + check(unknownType, solution); + } + for (TypeValue knownType : knownTypes.values()) { + check(knownType, solution); + } + + listener.done(solution, unknownTypes.keySet()); + + return solution; + } + + private void transitiveClosure(TypeValue current, Set visited) { + if (!visited.add(current)) { + return; + } + + for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) { + if (upperBound.isKnown()) { + continue; + } + transitiveClosure(upperBound, visited); + Set upperBounds = upperBound.getUpperBounds(); + for (TypeValue transitiveBound : upperBounds) { + expandSubtypingConstraint(current, transitiveBound); + } + } + } + + private void check(TypeValue typeValue, Solution solution) { + try { + JetType resultingType = typeValue.getType(); + JetType type = solution.getSubstitutor().substitute(resultingType, Variance.INVARIANT); // TODO + for (TypeValue upperBound : typeValue.getUpperBounds()) { + JetType boundingType = solution.getSubstitutor().substitute(upperBound.getType(), Variance.INVARIANT); + if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO + solution.registerError("Constraint violation: " + type + " is not a subtype of " + boundingType); + listener.error("Constraint violation: ", type, " :< ", boundingType); + } + } + for (TypeValue lowerBound : typeValue.getLowerBounds()) { + JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getType(), Variance.INVARIANT); + if (!typeChecker.isSubtypeOf(boundingType, type)) { + solution.registerError("Constraint violation: " + boundingType + " is not a subtype of " + type); + listener.error("Constraint violation: ", boundingType, " :< ", type); + } + } + } + catch (LoopInTypeVariableConstraintsException e) { + listener.error("Loop detected"); + solution.registerError("[TODO] Loop in constraints"); + } + } + + private static class Error implements SolutionStatus { + + private final String message; + + private Error(String message) { + this.message = message; + } + + @Override + public boolean isSuccessful() { + return false; + } + + @Override + public String toString() { + return message; + } + } + + public class Solution implements ConstraintSystemSolution { + private final TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() { + @Override + public TypeProjection get(TypeConstructor key) { + DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor(); + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor; + + if (!unknownTypes.containsKey(descriptor)) return null; + + TypeProjection typeProjection = new TypeProjection(getValue(descriptor)); + + listener.log(descriptor, " |-> ", typeProjection); + + return typeProjection; + } + return null; + } + + @Override + public boolean isEmpty() { + return false; + } + }); + + private SolutionStatus status; + + public Solution() { + this.status = SolutionStatus.SUCCESS; + } + + private Solution registerError(String message) { + status = new Error(message); + return this; + } + + @NotNull + @Override + public SolutionStatus getStatus() { + return status; + } + + @Override + public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) { + return getTypeVariable(typeParameterDescriptor).getType(); + } + + @NotNull + @Override + public TypeSubstitutor getSubstitutor() { + return typeSubstitutor; + } + + } + private static final class TypeConstraintBuilderAdapter implements TypingConstraints { + private final TypingConstraints delegate; + private final ConstraintResolutionListener listener; + + private TypeConstraintBuilderAdapter(TypingConstraints delegate, ConstraintResolutionListener listener) { + this.delegate = delegate; + this.listener = listener; + } + + @Override + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { + boolean result = delegate.assertEqualTypes(a, b, typeCheckingProcedure); + if (!result) { + listener.error("-- Failed to equate ", a, " and ", b); + } + return result; + } + + @Override + public boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b) { + boolean result = delegate.assertEqualTypeConstructors(a, b); + if (!result) { + listener.error("-- Type constructors are not equal: ", a, " and ", b); + } + return result; + } + + @Override + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) { + boolean result = delegate.assertSubtype(subtype, supertype, typeCheckingProcedure); + if (!result) { + listener.error("-- " + subtype + " can't be a subtype of " + supertype); + } + return result; + } + + @Override + public boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + boolean result = delegate.noCorrespondingSupertype(subtype, supertype); + if (!result) { + listener.error("-- " + subtype + " has no supertype corresponding to " + supertype); + } + return result; + } + } + +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java new file mode 100644 index 00000000000..d66578f1d83 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/ConstraintType.java @@ -0,0 +1,35 @@ +package org.jetbrains.jet.lang.resolve.calls.inference; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.types.JetType; + +import java.text.MessageFormat; + +/** + * @author abreslav + */ +public enum ConstraintType implements Comparable { + // The order of these constants DOES matter + // they are compared according to ordinal() values + // First element has the highest priority + RECEIVER("{0} is not a subtype of the expected receiver type {1}"), + VALUE_ARGUMENT("Type mismatch: argument type is {0}, but {1} was expected"), + EXPECTED_TYPE("Resulting type is {0} but {1} was expected"), + PARAMETER_BOUND("Type parameter bound is not satisfied: {0} is not a subtype of {1}"); + + private final String errorMessageTemplate; // {0} is subtype, {1} is supertye + + private ConstraintType(@NotNull String errorMessageTemplate) { + this.errorMessageTemplate = errorMessageTemplate; + } + + @NotNull + public SubtypingConstraint assertSubtyping(@NotNull JetType subtype, @NotNull JetType supertype) { + return new SubtypingConstraint(this, subtype, supertype); + } + + @NotNull + public String makeErrorMessage(@NotNull SubtypingConstraint constraint) { + return MessageFormat.format(errorMessageTemplate, constraint.getSubtype(), constraint.getSupertype()); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java index b6e5731f7cf..52edf22c3f0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/DebugConstraintResolutionListener.java @@ -23,9 +23,9 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi } @Override - public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - Map map = debugInfo.get(BOUNDS_FOR_UNKNOWNS); + Map map = debugInfo.get(BOUNDS_FOR_UNKNOWNS); if (map == null) { map = Maps.newLinkedHashMap(); debugInfo.set(BOUNDS_FOR_UNKNOWNS, map); @@ -34,9 +34,9 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi } @Override - public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForKnownType(JetType type, BoundsOwner typeValue) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; - Map map = debugInfo.get(BOUNDS_FOR_KNOWNS); + Map map = debugInfo.get(BOUNDS_FOR_KNOWNS); if (map == null) { map = Maps.newLinkedHashMap(); debugInfo.set(BOUNDS_FOR_KNOWNS, map); @@ -52,24 +52,30 @@ public class DebugConstraintResolutionListener implements ConstraintResolutionLi } @Override - public void log(Object message) { + public void log(Object... messageFragments) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; StringBuilder stringBuilder = debugInfo.get(LOG); if (stringBuilder == null) { stringBuilder = new StringBuilder(); debugInfo.set(LOG, stringBuilder); } - stringBuilder.append(message).append("\n"); + for (Object m : messageFragments) { + stringBuilder.append(m); + } + stringBuilder.append("\n"); } @Override - public void error(Object message) { + public void error(Object... messageFragments) { if (!ResolutionDebugInfo.isResolutionDebugEnabled()) return; StringBuilder stringBuilder = debugInfo.get(ERRORS); if (stringBuilder == null) { stringBuilder = new StringBuilder(); debugInfo.set(ERRORS, stringBuilder); } - stringBuilder.append(message).append("\n"); + for (Object m : messageFragments) { + stringBuilder.append(m); + } + stringBuilder.append("\n"); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/PrintingConstraintResolutionListener.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/PrintingConstraintResolutionListener.java index 3fe1a169eeb..ac3e3528b8d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/PrintingConstraintResolutionListener.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/PrintingConstraintResolutionListener.java @@ -12,13 +12,13 @@ import java.util.Set; public class PrintingConstraintResolutionListener implements ConstraintResolutionListener { @Override - public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForUnknown(TypeParameterDescriptor typeParameterDescriptor, BoundsOwner typeValue) { println("Constraints for " + typeParameterDescriptor); printTypeValue(typeValue); } @Override - public void constraintsForKnownType(JetType type, ConstraintSystemImpl.TypeValue typeValue) { + public void constraintsForKnownType(JetType type, BoundsOwner typeValue) { println("Constraints for " + type); printTypeValue(typeValue); } @@ -31,20 +31,24 @@ public class PrintingConstraintResolutionListener implements ConstraintResolutio } @Override - public void log(Object message) { - println(message); + public void log(Object... messageFragments) { + for (Object fragment : messageFragments) { + println(fragment); + } } @Override - public void error(Object message) { - println(message); + public void error(Object... messageFragments) { + for (Object fragment : messageFragments) { + println(fragment); + } } - private void printTypeValue(ConstraintSystemImpl.TypeValue typeValue) { - for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) { + private void printTypeValue(BoundsOwner typeValue) { + for (BoundsOwner bound : typeValue.getUpperBounds()) { println(" :< " + bound); } - for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) { + for (BoundsOwner bound : typeValue.getLowerBounds()) { println(" :> " + bound); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java new file mode 100644 index 00000000000..5f62fb11233 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/SubtypingConstraint.java @@ -0,0 +1,39 @@ +package org.jetbrains.jet.lang.resolve.calls.inference; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.types.JetType; + +/** + * @author abreslav + */ +public class SubtypingConstraint { + private final ConstraintType type; + private final JetType subtype; + private final JetType supertype; + + public SubtypingConstraint(@NotNull ConstraintType type, @NotNull JetType subtype, @NotNull JetType supertype) { + this.type = type; + this.subtype = subtype; + this.supertype = supertype; + } + + @NotNull + public JetType getSubtype() { + return subtype; + } + + @NotNull + public JetType getSupertype() { + return supertype; + } + + @NotNull + public ConstraintType getType() { + return type; + } + + @NotNull + public String getErrorMessage() { + return type.makeErrorMessage(this); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java new file mode 100644 index 00000000000..837036e003f --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/inference/TypeValue.java @@ -0,0 +1,82 @@ +package org.jetbrains.jet.lang.resolve.calls.inference; + +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.Variance; + +import java.util.Set; + +/** +* @author abreslav +*/ +public class TypeValue implements BoundsOwner { + private final Set upperBounds = Sets.newLinkedHashSet(); + private final Set lowerBounds = Sets.newLinkedHashSet(); + + private final Variance positionVariance; + private final TypeParameterDescriptor typeParameterDescriptor; // Null for known types + private final JetType originalType; + private JetType value; // For an unknown — the value found by constraint resolution, for a known — just it's value + + // Unknown type + public TypeValue(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { + this.positionVariance = positionVariance; + this.typeParameterDescriptor = typeParameterDescriptor; + this.originalType = typeParameterDescriptor.getDefaultType(); + } + + // Known type + public TypeValue(@NotNull JetType knownType) { + this.positionVariance = null; + this.typeParameterDescriptor = null; + this.originalType = knownType; + } + + public boolean isKnown() { + return typeParameterDescriptor == null; + } + + public TypeParameterDescriptor getTypeParameterDescriptor() { + return typeParameterDescriptor; + } + + @Override + @NotNull + public Set getUpperBounds() { + return upperBounds; + } + + @Override + @NotNull + public Set getLowerBounds() { + return lowerBounds; + } + + @NotNull + public JetType getType() { + return value; + } + + @NotNull + public JetType getOriginalType() { + return originalType; + } + + public void addUpperBound(@NotNull TypeValue bound) { + upperBounds.add(bound); + } + + public void addLowerBound(@NotNull TypeValue bound) { + lowerBounds.add(bound); + } + + public void setValue(@NotNull JetType value) { + this.value = value; + } + + public boolean hasValue() { + return value != null; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index 1c77b65f443..ee76f1ed2e9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -203,7 +203,7 @@ public class ErrorUtils { } public static boolean isError(@NotNull DeclarationDescriptor candidate) { - return candidate.getContainingDeclaration() == getErrorClass() || candidate == ERROR_MODULE; + return candidate == getErrorClass() || candidate.getContainingDeclaration() == getErrorClass() || candidate == ERROR_MODULE; } private static class ErrorTypeImpl implements JetType { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index e0e2a35b24d..55c861b18c8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -1,19 +1,41 @@ package org.jetbrains.jet.lang.types; +import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @author abreslav */ public class TypeSubstitutor { + public static TypeSubstitutor makeConstantSubstitutor(Collection typeParameterDescriptors, JetType type) { + final Set constructors = Sets.newHashSet(); + for (TypeParameterDescriptor typeParameterDescriptor : typeParameterDescriptors) { + constructors.add(typeParameterDescriptor.getTypeConstructor()); + } + final TypeProjection projection = new TypeProjection(type); + + return create(new TypeSubstitution() { + @Override + public TypeProjection get(TypeConstructor key) { + if (constructors.contains(key)) { + return projection; + } + return null; + } + + @Override + public boolean isEmpty() { + return false; + } + }); + } + public interface TypeSubstitution { TypeSubstitution EMPTY = new TypeSubstitution() { @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java index 7147158c66c..691966d302d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java @@ -46,7 +46,7 @@ public class JetTypeChecker { private static class TypeCheckerTypingConstraints implements TypingConstraints { @Override - public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure) { return typeCheckingProcedure.equalTypes(a, b); // return TypeUtils.equalTypes(a, b); } @@ -57,7 +57,7 @@ public class JetTypeChecker { } @Override - public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure) { + public boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure) { return typeCheckingProcedure.isSubtypeOf(subtype, supertype); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypingConstraints.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypingConstraints.java index 0276f816184..754bff7f5f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypingConstraints.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypingConstraints.java @@ -8,11 +8,11 @@ import org.jetbrains.jet.lang.types.TypeConstructor; * Methods of this class return true to continue type checking and false to fail */ public interface TypingConstraints { - boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, TypeCheckingProcedure typeCheckingProcedure); + boolean assertEqualTypes(@NotNull JetType a, @NotNull JetType b, @NotNull TypeCheckingProcedure typeCheckingProcedure); boolean assertEqualTypeConstructors(@NotNull TypeConstructor a, @NotNull TypeConstructor b); - boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, TypeCheckingProcedure typeCheckingProcedure); + boolean assertSubtype(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull TypeCheckingProcedure typeCheckingProcedure); boolean noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype); } diff --git a/compiler/testData/codegen/inputStreamIterator.jet b/compiler/testData/codegen/inputStreamIterator.jet index 7be02b077f2..85ff66b2ba7 100644 --- a/compiler/testData/codegen/inputStreamIterator.jet +++ b/compiler/testData/codegen/inputStreamIterator.jet @@ -1,3 +1,4 @@ +import std.* import std.io.* import java.io.* diff --git a/compiler/testData/codegen/regressions/kt259.jet b/compiler/testData/codegen/regressions/kt259.jet index 59a99b1bcbb..ad996781b9f 100644 --- a/compiler/testData/codegen/regressions/kt259.jet +++ b/compiler/testData/codegen/regressions/kt259.jet @@ -1,4 +1,5 @@ class A() {} + open class B() { fun isT (a : Any?) : Boolean { return a is T @@ -167,7 +168,6 @@ fun t26 () : Boolean { } fun box() : String { -/* if(!t1()) { return "t1 failed" } @@ -243,7 +243,6 @@ fun box() : String { if(!t25()) { return "t25 failed" } - */ if(!t26()) { return "t26 failed" } diff --git a/compiler/testData/codegen/regressions/kt785.jet b/compiler/testData/codegen/regressions/kt785.jet new file mode 100644 index 00000000000..1b10c8c73d7 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt785.jet @@ -0,0 +1,13 @@ +class A() { + var x : Int = 0 + + var z = { () => + x++ + } +} + +fun box() : String { + val a = A() + a.z() //problem is here + return if (a.x == 1) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/regressions/kt796_797.jet b/compiler/testData/codegen/regressions/kt796_797.jet new file mode 100644 index 00000000000..03ae120b510 --- /dev/null +++ b/compiler/testData/codegen/regressions/kt796_797.jet @@ -0,0 +1,8 @@ +fun Array?.get(i : Int?) = this.sure().get(i.sure()) +fun array(vararg t : T) : Array = t + +fun box() : String { + val a : Array? = array("Str", "Str2") + val i : Int? = 1 + return if(a[i] == "Str2") "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/typeInfo/inheritance.jet b/compiler/testData/codegen/typeInfo/inheritance.jet index 225bda1f665..3ee02657f34 100644 --- a/compiler/testData/codegen/typeInfo/inheritance.jet +++ b/compiler/testData/codegen/typeInfo/inheritance.jet @@ -1,4 +1,4 @@ -open class A () { +open class A () { fun plus(e: T) = B (e) } @@ -6,4 +6,6 @@ class B (val e: T) : A() { fun add() = B (e) } -fun box() = if( A().plus("239").add().e == "239" ) "OK" else "fail" \ No newline at end of file +fun box() : String { + return if(A().plus("239").add().e == "239" ) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/typeInfo/inner.jet b/compiler/testData/codegen/typeInfo/inner.jet index 49db9252b35..62dad284a09 100644 --- a/compiler/testData/codegen/typeInfo/inner.jet +++ b/compiler/testData/codegen/typeInfo/inner.jet @@ -4,7 +4,6 @@ class Box() { } class Inner2() : Inner() { - } fun inner() = Inner2() diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java new file mode 100644 index 00000000000..2d1e5d107fc --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java @@ -0,0 +1,6 @@ +class ExtendsAbstractListT { + { + Mine mine = null; + java.util.List list = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt new file mode 100644 index 00000000000..472c847fd89 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt @@ -0,0 +1 @@ +abstract class Mine() : java.util.AbstractList() diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java new file mode 100644 index 00000000000..699606e6a43 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java @@ -0,0 +1,7 @@ + +class PlainExtendsListString { + { + Mine mine = null; + java.util.List list = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt new file mode 100644 index 00000000000..8de577c0bcc --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt @@ -0,0 +1 @@ +abstract class Mine : java.util.List diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java new file mode 100644 index 00000000000..5664662764e --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java @@ -0,0 +1,7 @@ + +class ImplementsMapPP { + { + Mine mine = null; + java.util.Map map = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt new file mode 100644 index 00000000000..a973a76c33e --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt @@ -0,0 +1 @@ +abstract class Mine : java.util.Map diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java new file mode 100644 index 00000000000..72b7170231a --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java @@ -0,0 +1,8 @@ + +class Question { + // id2 is to prevent java type parameter type inference + static T id2(T p) { return p; } + { + java.util.List s = id2(namespace.id((jet.typeinfo.TypeInfo) null, null)); + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt new file mode 100644 index 00000000000..40dc99ff079 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt @@ -0,0 +1,3 @@ +import java.util.List + +fun > id(p: P1) = p diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java new file mode 100644 index 00000000000..f525b5923a5 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java @@ -0,0 +1,8 @@ + +class Question { + // id2 is to prevent java type parameter type inference + static T id2(T p) { return p; } + { + String s = id2(namespace.id((jet.typeinfo.TypeInfo) null, null)); + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt new file mode 100644 index 00000000000..e360425de59 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt @@ -0,0 +1 @@ +fun id(p: T) = p diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index 25c697c6484..88e445a6bb1 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -24,7 +24,7 @@ public class ClassGenTest extends CodegenTestCase { public void testArrayListInheritance() throws Exception { loadFile("classes/inheritingFromArrayList.jet"); - + System.out.println(generateToText()); final Class aClass = loadClass("Foo", generateClassesInFile()); assertInstanceOf(aClass.newInstance(), List.class); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 7b5a7a33e7a..431400d66bd 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -81,6 +81,10 @@ public class FunctionGenTest extends CodegenTestCase { blackBoxFile("regressions/kt395.jet"); } + public void testKt785 () { +// blackBoxFile("regressions/kt785.jet"); + } + public void testFunction () throws InvocationTargetException, IllegalAccessException { blackBoxFile("functions/functionExpression.jet"); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index 85b9dae07d8..b2396c96af6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -140,7 +140,7 @@ public class TypeInfoTest extends CodegenTestCase { public void testInner() throws Exception { blackBoxFile("typeInfo/inner.jet"); -// System.out.println(generateToText()); + System.out.println(generateToText()); } public void testInheritance() throws Exception { @@ -148,4 +148,3 @@ public class TypeInfoTest extends CodegenTestCase { System.out.println(generateToText()); } } - diff --git a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java index e08b515771c..4a68f35e678 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java @@ -74,4 +74,8 @@ public class VarArgTest extends CodegenTestCase { createEnvironmentWithFullJdk(); blackBoxFile("regressions/kt581.jet"); } + + public void testKt797() { + blackBoxFile("regressions/kt796_797.jet"); + } } diff --git a/examples/src/benchmarks/FList.java b/examples/src/benchmarks/FList.java new file mode 100644 index 00000000000..694dd70ac96 --- /dev/null +++ b/examples/src/benchmarks/FList.java @@ -0,0 +1,86 @@ +import java.util.NoSuchElementException; + +abstract public class FList { + abstract T getHead(); + + abstract FList getTail(); + + abstract FList plus(T element); + + static class Empty extends FList { + + @Override + T getHead() { + throw new NoSuchElementException(); + } + + @Override + FList getTail() { + throw new NoSuchElementException(); + } + + @Override + FList plus(T element) { + return new OneElementList(element); + } + } + + static class OneElementList extends FList { + private T element; + + public OneElementList(T element) { + super(); + this.element = element; + } + + @Override + T getHead() { + return element; + } + + @Override + FList getTail() { + return new Empty(); + } + + @Override + FList plus(T element) { + return new StandardList(element, this); + } + } + + private static class StandardList extends FList { + private T head; + private FList tail; + + public StandardList(T head, FList tail) { + this.head = head; + this.tail = tail; + } + + @Override + T getHead() { + return head; + } + + @Override + FList getTail() { + return tail; + } + + @Override + FList plus(T element) { + return new StandardList(element, this); + } + } + + public static void main(String[] args) { + for(int k = 0; k != 10; ++k) { + long start = System.currentTimeMillis(); + FList list = new Empty(); + for(int i = 0; i != 5000000; ++i) + list = list.plus(i); + System.out.println(System.currentTimeMillis()-start); + } + } +} diff --git a/examples/src/benchmarks/FList.kt b/examples/src/benchmarks/FList.kt new file mode 100644 index 00000000000..5d806215920 --- /dev/null +++ b/examples/src/benchmarks/FList.kt @@ -0,0 +1,70 @@ +namespace flist + +abstract class FList { + abstract val head : T + abstract val tail : FList + + abstract fun plus(element: T) : FList +} + +class EmptyFList() : FList { + override val head: T + get() = throw java.util.NoSuchElementException() + + override val tail : EmptyFList + get() = EmptyFList() + + override fun plus(element: T) : FList = OneElementFList(element) +} + +class OneElementFList (override val head: T): FList { + override val tail : EmptyFList + get() = EmptyFList() + + override fun plus(element: T) : FList = StandardFList(element, this) +} + +class StandardFList (override val head: T, override val tail: FList) : FList { + override fun plus(element: T) : FList = StandardFList(element, this) +} + +fun FList.plus2(element: T): FList = + when(this) { + is EmptyFList => OneElementFList(element) + else => StandardFList(element, this) + } + +fun FList.plus3(element: T) : FList = + if(this is EmptyFList<*>) + OneElementFList(element) + else + StandardFList(element, this) + +fun main(args: Array) { + for(k in 0..3) { + val start0 = System.currentTimeMillis() + + var flist0 : FList = EmptyFList() + for(i in 0..5000000) + flist0 = flist0 + i + + System.out?.println(System.currentTimeMillis() - start0) + + val start = System.currentTimeMillis() + + var flist : FList = EmptyFList() + for(i in 0..5000000) + flist = flist.plus2(i) + + System.out?.println(System.currentTimeMillis() - start) + + val start2 = System.currentTimeMillis() + + var flist2 : FList = EmptyFList() + for(i in 0..5000000) + flist2 = flist2.plus3(i) + + System.out?.println(System.currentTimeMillis() - start2) + System.out?.println() + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java index 6f7a57c8492..eaec4204faf 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.plugin.completion; import com.intellij.codeInsight.completion.*; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.patterns.PlatformPatterns; import com.intellij.patterns.PsiElementPattern; @@ -11,6 +12,7 @@ import com.intellij.psi.filters.position.FilterPattern; import com.intellij.psi.filters.position.LeftNeighbour; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.plugin.completion.handlers.JetKeywordInsertHandler; /** * A keyword contributor for Kotlin @@ -21,7 +23,9 @@ import org.jetbrains.annotations.NotNull; public class JetKeywordCompletionContributor extends CompletionContributor { private static class JetTopKeywordCompletionProvider extends CompletionProvider { - + + private final static InsertHandler KEYWORDS_INSERT_HANDLER = new JetKeywordInsertHandler(); + private final static String[] COMPLETE_KEYWORD = new String[] { "namespace", "as", "type", "class", "this", "super", "val", "var", "fun", "for", "null", "true", "false", "is", "in", "throw", "return", "break", "continue", "object", "if", "try", "else", "while", @@ -32,18 +36,19 @@ public class JetKeywordCompletionContributor extends CompletionContributor { "import", "where", "by", "get", "set", "abstract", "enum", "open", "annotation", "override", "private", "public", "internal", "protected", "catch", "out", "vararg", "inline", "finally", "final", "ref" }; - + @Override protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) { for (String keyword : COMPLETE_KEYWORD) { - result.addElement(LookupElementBuilder.create(keyword).setBold()); + + result.addElement(LookupElementBuilder.create(keyword).setInsertHandler(KEYWORDS_INSERT_HANDLER).setBold()); } for (String softKeyword : COMPLETE_SOFT_KEYWORDS) { - result.addElement(LookupElementBuilder.create(softKeyword)); + result.addElement(LookupElementBuilder.create(softKeyword).setInsertHandler(KEYWORDS_INSERT_HANDLER)); } } } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java new file mode 100644 index 00000000000..68aafbc70a1 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java @@ -0,0 +1,38 @@ +package org.jetbrains.jet.plugin.completion.handlers; + +import com.intellij.codeInsight.completion.InsertHandler; +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.editor.Editor; + +/** + * Inserts '()' after function proposal insert. + * + * @author Nikolay Krasko + */ +public class JetFunctionInsertHandler implements InsertHandler { + + public enum CaretPosition { IN_BRACKETS, AFTER_BRACKETS } + + private final CaretPosition caretPosition; + + public JetFunctionInsertHandler(CaretPosition caretPosition) { + this.caretPosition = caretPosition; + } + + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + int startOffset = context.getStartOffset(); + int lookupStringLength = item.getLookupString().length(); + int endOffset = startOffset + lookupStringLength; + + context.getDocument().insertString(endOffset, "()"); + + Editor editor = context.getEditor(); + if (caretPosition == CaretPosition.IN_BRACKETS) { + editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 1); + } else { + editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 2); + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetKeywordInsertHandler.java b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetKeywordInsertHandler.java new file mode 100644 index 00000000000..2424d1a2c7a --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetKeywordInsertHandler.java @@ -0,0 +1,34 @@ +package org.jetbrains.jet.plugin.completion.handlers; + +import com.google.common.collect.Sets; +import com.intellij.codeInsight.completion.InsertHandler; +import com.intellij.codeInsight.completion.InsertionContext; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; + +import java.util.Set; + +/** + * @author Nikolay Krasko + */ +public class JetKeywordInsertHandler implements InsertHandler { + + private final static Set NO_SPACE_AFTER = Sets.newHashSet("this", "super", "This", "true", "false", "null"); + + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + String keyword = item.getLookupString(); + + // Add space after keyword + if (!NO_SPACE_AFTER.contains(keyword)) { + Editor editor = context.getEditor(); + Document document = editor.getDocument(); + + int offset = context.getStartOffset() + keyword.length(); + context.setAddCompletionChar(false); + document.insertString(offset, " "); + editor.getCaretModel().moveToOffset(editor.getCaretModel().getOffset() + 1); + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java index 94a47c390c7..4b9a6fbc102 100644 --- a/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java +++ b/idea/src/org/jetbrains/jet/plugin/internal/resolvewindow/ResolveToolwindow.java @@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.ResolutionDebugInfo; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.calls.inference.BoundsOwner; import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; @@ -190,9 +191,9 @@ public class ResolveToolwindow extends JPanel { result.append("Log: \n").append(log).append(bar); } - Map knowns = debugInfo.get(BOUNDS_FOR_KNOWNS); + Map knowns = debugInfo.get(BOUNDS_FOR_KNOWNS); renderMap(knowns, result); - Map unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS); + Map unknowns = debugInfo.get(BOUNDS_FOR_UNKNOWNS); renderMap(unknowns, result); result.append(bar); @@ -205,17 +206,17 @@ public class ResolveToolwindow extends JPanel { return result.toString(); } - private void renderMap(Map map, StringBuilder builder) { + private void renderMap(Map map, StringBuilder builder) { if (map == null) return; - for (Map.Entry entry : map.entrySet()) { + for (Map.Entry entry : map.entrySet()) { K key = entry.getKey(); - ConstraintSystemImpl.TypeValue typeValue = entry.getValue(); + BoundsOwner typeValue = entry.getValue(); builder.append("Bounds for ").append(key).append("\n"); - for (ConstraintSystemImpl.TypeValue bound : typeValue.getLowerBounds()) { + for (BoundsOwner bound : typeValue.getLowerBounds()) { builder.append(" >: ").append(bound).append("\n"); } - for (ConstraintSystemImpl.TypeValue bound : typeValue.getUpperBounds()) { + for (BoundsOwner bound : typeValue.getUpperBounds()) { builder.append(" <: ").append(bound).append("\n"); } } diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 3239d3c47ef..7224322b46e 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -17,10 +17,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintResolutionListener; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemImpl; -import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution; +import org.jetbrains.jet.lang.resolve.calls.inference.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; @@ -28,15 +25,25 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; +import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler; import org.jetbrains.jet.resolve.DescriptorRenderer; import java.util.List; import java.util.Set; +import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.RECEIVER; + /** * @author yole */ class JetSimpleNameReference extends JetPsiReference { + + private final static JetFunctionInsertHandler EMPTY_FUNCTION_HANDLER = new JetFunctionInsertHandler( + JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS); + + private final static JetFunctionInsertHandler PARAMS_FUNCTION_HANDLER = new JetFunctionInsertHandler( + JetFunctionInsertHandler.CaretPosition.IN_BRACKETS); + private final JetSimpleNameExpression myExpression; public JetSimpleNameReference(JetSimpleNameExpression jetSimpleNameExpression) { @@ -135,10 +142,12 @@ class JetSimpleNameReference extends JetPsiReference { String typeText = ""; String tailText = ""; boolean tailTextGrayed = false; + if (descriptor instanceof FunctionDescriptor) { FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; JetType returnType = functionDescriptor.getReturnType(); typeText = DescriptorRenderer.TEXT.renderType(returnType); + tailText = "(" + StringUtil.join(functionDescriptor.getValueParameters(), new Function() { @Override public String fun(ValueParameterDescriptor valueParameterDescriptor) { @@ -146,6 +155,14 @@ class JetSimpleNameReference extends JetPsiReference { DescriptorRenderer.TEXT.renderType(valueParameterDescriptor.getOutType()); } }, ",") + ")"; + + // TODO: A special case when it's impossible to resolve type parameters from arguments. Need '<' caret '>' + // TODO: Support omitting brackets for one argument functions + if (functionDescriptor.getValueParameters().isEmpty()) { + element = element.setInsertHandler(EMPTY_FUNCTION_HANDLER); + } else { + element = element.setInsertHandler(PARAMS_FUNCTION_HANDLER); + } } else if (descriptor instanceof VariableDescriptor) { JetType outType = ((VariableDescriptor) descriptor).getOutType(); @@ -170,8 +187,8 @@ class JetSimpleNameReference extends JetPsiReference { return result.toArray(); } - /** - * Checks that receiver declaration could be resolved to call expected receiver. + /* + * Checks if receiver declaration could be resolved to call expected receiver. */ private static boolean checkReceiverResolution ( @NotNull ReceiverDescriptor expectedReceiver, @@ -184,7 +201,7 @@ class JetSimpleNameReference extends JetPsiReference { ReceiverDescriptor receiverParameter = receiverArgument.getReceiverParameter(); if (expectedReceiver.exists() && receiverParameter.exists()) { - constraintSystem.addSubtypingConstraint(expectedReceiver.getType(), receiverParameter.getType()); + constraintSystem.addSubtypingConstraint(RECEIVER.assertSubtyping(expectedReceiver.getType(), receiverParameter.getType())); } else if (expectedReceiver.exists() || receiverParameter.exists()) { // Only one of receivers exist diff --git a/idea/testData/completion/basic/ExtendClassName.kt b/idea/testData/completion/basic/ExtendClassName.kt index 47daf28eff9..c4ae4f6575d 100644 --- a/idea/testData/completion/basic/ExtendClassName.kt +++ b/idea/testData/completion/basic/ExtendClassName.kt @@ -10,4 +10,4 @@ class A() : My { } } -// EXIST: MySecondClass, MyFirstClass \ No newline at end of file +// EXIST: MySecondClass, MyFirstClass diff --git a/idea/testData/completion/handlers/NoParamsFunction.kt b/idea/testData/completion/handlers/NoParamsFunction.kt new file mode 100644 index 00000000000..120b5e55d02 --- /dev/null +++ b/idea/testData/completion/handlers/NoParamsFunction.kt @@ -0,0 +1,8 @@ +fun test() { +} + +fun other() { + te +} + +// INSERT: test \ No newline at end of file diff --git a/idea/testData/completion/handlers/NoParamsFunction.kt.after b/idea/testData/completion/handlers/NoParamsFunction.kt.after new file mode 100644 index 00000000000..920873c0b51 --- /dev/null +++ b/idea/testData/completion/handlers/NoParamsFunction.kt.after @@ -0,0 +1,8 @@ +fun test() { +} + +fun other() { + test() +} + +// INSERT: test \ No newline at end of file diff --git a/idea/testData/completion/handlers/ParamsFunction.kt b/idea/testData/completion/handlers/ParamsFunction.kt new file mode 100644 index 00000000000..c7910930150 --- /dev/null +++ b/idea/testData/completion/handlers/ParamsFunction.kt @@ -0,0 +1,6 @@ +fun test(a: Int) { +} + +fun other() { + te +} \ No newline at end of file diff --git a/idea/testData/completion/handlers/ParamsFunction.kt.after b/idea/testData/completion/handlers/ParamsFunction.kt.after new file mode 100644 index 00000000000..175892cc3a5 --- /dev/null +++ b/idea/testData/completion/handlers/ParamsFunction.kt.after @@ -0,0 +1,6 @@ +fun test(a: Int) { +} + +fun other() { + test() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java new file mode 100644 index 00000000000..f265bde4714 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java @@ -0,0 +1,28 @@ +package org.jetbrains.jet.completion.handlers; + +import com.intellij.codeInsight.completion.LightCompletionTestCase; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.io.File; + +/** + * @author Nikolay Krasko + */ +public class FunctionsHandlerTest extends LightCompletionTestCase { + + public void testNoParamsFunction() { + configureByFile("NoParamsFunction.kt"); + checkResultByFile("NoParamsFunction.kt.after"); + } + + public void testFunctionWithParams() { + configureByFile("ParamsFunction.kt"); + checkResultByFile("ParamsFunction.kt.after"); + } + + @Override + protected String getTestDataPath() { + return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/").getPath() + + File.separator; + } +} diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/KeywordsHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/KeywordsHandlerTest.java new file mode 100644 index 00000000000..4b6193b2549 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/completion/handlers/KeywordsHandlerTest.java @@ -0,0 +1,31 @@ +package org.jetbrains.jet.completion.handlers; + +import com.intellij.codeInsight.completion.LightCompletionTestCase; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.io.File; +import java.io.IOException; + +/** + * @author Nikolay Krasko + */ +public class KeywordsHandlerTest extends LightCompletionTestCase { + + public void testSpaceAfter() throws IOException { + configureFromFileText("Test.kt", "protecte"); + complete(); + checkResultByText("protected "); + } + + public void testNoSpaceAfter() throws IOException { + configureFromFileText("Test.kt", "nul"); + complete(); + checkResultByText("null"); + } + + @Override + protected String getTestDataPath() { + return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/").getPath() + + File.separator; + } +} diff --git a/stdlib/ktSrc/Arrays.kt b/stdlib/ktSrc/Arrays.kt new file mode 100644 index 00000000000..197cd1c236c --- /dev/null +++ b/stdlib/ktSrc/Arrays.kt @@ -0,0 +1,29 @@ +namespace std + +import java.io.ByteArrayInputStream + +// Array "constructor" +inline fun array(vararg t : T) : Array = t + +// "constructors" for primitive types array +inline fun doubleArray(vararg content : Double) = content + +inline fun floatArray(vararg content : Float) = content + +inline fun longArray(vararg content : Long) = content + +inline fun intArray(vararg content : Int) = content + +inline fun charArray(vararg content : Char) = content + +inline fun shortArray(vararg content : Short) = content + +inline fun byteArray(vararg content : Byte) = content + +inline fun booleanArray(vararg content : Boolean) = content + +inline val ByteArray.inputStream : ByteArrayInputStream + get() = ByteArrayInputStream(this) + +inline fun ByteArray.inputStream(offset: Int, length: Int) = ByteArrayInputStream(this, offset, length) + diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/JavaIo.kt similarity index 78% rename from stdlib/ktSrc/StandardLibrary.kt rename to stdlib/ktSrc/JavaIo.kt index 999cecbad2c..71ab785f556 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/JavaIo.kt @@ -27,47 +27,6 @@ namespace io { inline fun println(message : CharArray) { System.out?.println(message) } inline fun println() { System.out?.println() } - val ByteArray.inputStream : ByteArrayInputStream - get() = ByteArrayInputStream(this) - -// inline fun ByteArray.inputStream(offset: Int, length: Int) = ByteArrayInputStream(this, offset, length) - - fun InputStream.iterator() : ByteIterator = - object: ByteIterator() { - override val hasNext : Boolean - get() = available() > 0 - - override fun nextByte() = read().byt - } - - val InputStream.buffered : BufferedInputStream - get() = if(this is BufferedInputStream) this else BufferedInputStream(this) - -// inline fun InputStream.buffered(bufferSize: Int) = BufferedInputStream(this, bufferSize) - - val InputStream.reader : InputStreamReader - get() = InputStreamReader(this) - - val InputStream.bufferedReader : BufferedReader - get() = BufferedReader(reader) - -/* - inline fun InputStream.reader(charset: Charset) : InputStreamReader = InputStreamReader(this, charset) - - inline fun InputStream.reader(charsetName: String) = InputStreamReader(this, charsetNme) - - inline fun InputStream.reader(charset: Charset) = InputStreamReader(this, charset) - - inline fun InputStream.reader(charsetDecoder: CharsetDecoder) = InputStreamReader(this, charsetDecoder) -*/ - -// val Reader.buffered : BufferedReader -// get() = if(this instanceof BufferedReader) this else BufferedReader(this) - -// inline fun Reader.buffered(bufferSize: Int) = BufferedReader(this, bufferSize) - -// val String.reader = StringReader(this) - private val stdin : BufferedReader = BufferedReader(InputStreamReader(object : InputStream() { override fun read() : Int { return System.`in`?.read() ?: -1 @@ -106,5 +65,35 @@ namespace io { } })) - fun readLine() : String? = stdin.readLine() + inline fun readLine() : String? = stdin.readLine() + + fun InputStream.iterator() : ByteIterator = + object: ByteIterator() { + override val hasNext : Boolean + get() = available() > 0 + + override fun nextByte() = read().byt + } + + inline fun InputStream.buffered(bufferSize: Int) = BufferedInputStream(this, bufferSize) + + inline val InputStream.reader : InputStreamReader + get() = InputStreamReader(this) + + inline val InputStream.bufferedReader : BufferedReader + get() = BufferedReader(reader) + + inline fun InputStream.reader(charset: Charset) : InputStreamReader = InputStreamReader(this, charset) + + inline fun InputStream.reader(charsetName: String) = InputStreamReader(this, charsetName) + + inline fun InputStream.reader(charsetDecoder: CharsetDecoder) = InputStreamReader(this, charsetDecoder) + + inline val InputStream.buffered : BufferedInputStream + get() = if(this is BufferedInputStream) this else BufferedInputStream(this) + +// inline val Reader.buffered : BufferedReader +// get() = if(this is BufferedReader) this else BufferedReader(this) + + inline fun Reader.buffered(bufferSize: Int) = BufferedReader(this, bufferSize) } \ No newline at end of file diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index ba3c74b8adb..a75df8656d9 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -1,11 +1,9 @@ -namespace std +namespace std.util -namespace util { - import java.util.* +import java.util.* - val Collection<*>.size : Int - get() = size() +val Collection<*>.size : Int + get() = size() - val Collection<*>.empty : Boolean - get() = isEmpty() -} \ No newline at end of file +val Collection<*>.empty : Boolean + get() = isEmpty() diff --git a/stdlib/ktSrc/String.kt b/stdlib/ktSrc/String.kt new file mode 100644 index 00000000000..4df7c099d29 --- /dev/null +++ b/stdlib/ktSrc/String.kt @@ -0,0 +1,62 @@ +namespace std + +import java.io.StringReader + +inline fun T?.plus(str: String?) : String { return toString() + str } + +inline fun String.lastIndexOf(s: String) = (this as java.lang.String).lastIndexOf(s) + +inline fun String.lastIndexOf(s: Char) = (this as java.lang.String).lastIndexOf(s.toString()) } + +inline fun String.indexOf(s : String) = (this as java.lang.String).indexOf(s) + +inline fun String.indexOf(p0 : String, p1 : Int) = (this as java.lang.String).indexOf(p0, p1) + +inline fun String.replaceAll(s: String, s1 : String) = (this as java.lang.String).replaceAll(s, s1).sure() + +inline fun String.trim() = (this as java.lang.String).trim().sure() + +inline fun String.toUpperCase() = (this as java.lang.String).toUpperCase().sure() + +inline fun String.toLowerCase() = (this as java.lang.String).toLowerCase().sure() + +inline fun String.length() = (this as java.lang.String).length() + +inline fun String.getBytes() = (this as java.lang.String).getBytes().sure() + +inline fun String.toCharArray() = (this as java.lang.String).toCharArray().sure() + +inline fun String.format(s : String, vararg objects : Any?) = java.lang.String.format(s, objects).sure() + +inline fun String.split(s : String) = (this as java.lang.String).split(s) + +inline fun String.substring(i : Int) = (this as java.lang.String).substring(i).sure() + +inline fun String.substring(i0 : Int, i1 : Int) = (this as java.lang.String).substring(i0, i1).sure() + +inline val String.size : Int + get() = length() + +inline val String.reader : StringReader + get() = StringReader(this) + +// "constructors" for String + +inline fun String(bytes : ByteArray, i : Int, i1 : Int, s : String) = java.lang.String(bytes, i, i1, s) as String + +inline fun String(bytes : ByteArray, i : Int, i1 : Int, charset : java.nio.charset.Charset) = java.lang.String(bytes, i, i1, charset) as String + +inline fun String(bytes : ByteArray, s : String?) = java.lang.String(bytes, s) as String + +inline fun String(bytes : ByteArray, charset : java.nio.charset.Charset) = java.lang.String(bytes, charset) as String + +inline fun String(bytes : ByteArray, i : Int, i1 : Int) = java.lang.String(bytes, i, i1) as String + +inline fun String(bytes : ByteArray) = java.lang.String(bytes) as String + +inline fun String(chars : CharArray) = java.lang.String(chars) as String + +inline fun String(stringBuffer : java.lang.StringBuffer) = java.lang.String(stringBuffer) as String + +inline fun String(stringBuilder : java.lang.StringBuilder) = java.lang.String(stringBuilder) as String + diff --git a/stdlib/src/jet/DefaultJetObject.java b/stdlib/src/jet/DefaultJetObject.java index 4070c14eb5d..736606a70d6 100644 --- a/stdlib/src/jet/DefaultJetObject.java +++ b/stdlib/src/jet/DefaultJetObject.java @@ -23,4 +23,9 @@ public class DefaultJetObject implements JetObject { public final TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } diff --git a/stdlib/src/jet/IntRange.java b/stdlib/src/jet/IntRange.java index 71d49ed0a73..13811dbba40 100644 --- a/stdlib/src/jet/IntRange.java +++ b/stdlib/src/jet/IntRange.java @@ -47,7 +47,12 @@ public final class IntRange implements Range, Iterable, JetObj public TypeInfo getTypeInfo() { return typeInfo; } - + + @Override + public JetObject getOuterObject() { + return null; + } + public static IntRange count(int length) { return new IntRange(0, length); } @@ -95,5 +100,10 @@ public final class IntRange implements Range, Iterable, JetObj public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } } diff --git a/stdlib/src/jet/JetObject.java b/stdlib/src/jet/JetObject.java index c06fd1f755a..96f17a323b6 100644 --- a/stdlib/src/jet/JetObject.java +++ b/stdlib/src/jet/JetObject.java @@ -4,7 +4,9 @@ import jet.typeinfo.TypeInfo; /** * @author abreslav + * @author alex.tkachman */ public interface JetObject { TypeInfo getTypeInfo(); + JetObject getOuterObject(); } diff --git a/stdlib/src/jet/LongRange.java b/stdlib/src/jet/LongRange.java index e0a358599fb..ed94c76cb31 100644 --- a/stdlib/src/jet/LongRange.java +++ b/stdlib/src/jet/LongRange.java @@ -48,6 +48,11 @@ public final class LongRange implements Range, Iterable, JetObject { return typeInfo; } + @Override + public JetObject getOuterObject() { + return null; + } + public static IntRange count(int length) { return new IntRange(0, length); } @@ -95,5 +100,10 @@ public final class LongRange implements Range, Iterable, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } } diff --git a/stdlib/src/jet/Tuple0.java b/stdlib/src/jet/Tuple0.java index 34d12022230..a4823e1dd5e 100644 --- a/stdlib/src/jet/Tuple0.java +++ b/stdlib/src/jet/Tuple0.java @@ -31,4 +31,9 @@ public class Tuple0 implements JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } \ No newline at end of file diff --git a/stdlib/src/jet/runtime/ArrayIterator.java b/stdlib/src/jet/runtime/ArrayIterator.java index 55d4e0a9cd9..0b05941e507 100644 --- a/stdlib/src/jet/runtime/ArrayIterator.java +++ b/stdlib/src/jet/runtime/ArrayIterator.java @@ -37,7 +37,12 @@ public abstract class ArrayIterator implements Iterator, JetObject { @Override public TypeInfo getTypeInfo() { - return TypeInfo.getTypeInfo(GenericIterator.class, false, null, new TypeInfoProjection[] {(TypeInfoProjection) elementTypeInfo}); + return TypeInfo.getTypeInfo(GenericIterator.class, false, new TypeInfoProjection[] {(TypeInfoProjection) elementTypeInfo}); + } + + @Override + public JetObject getOuterObject() { + return null; } } @@ -69,6 +74,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static ByteIterator iterator(byte[] array) { @@ -99,6 +109,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static ShortIterator iterator(short[] array) { @@ -129,6 +144,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static IntIterator iterator(int[] array) { @@ -159,6 +179,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static LongIterator iterator(long[] array) { @@ -189,6 +214,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static FloatIterator iterator(float[] array) { @@ -219,6 +249,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static DoubleIterator iterator(double[] array) { @@ -249,6 +284,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static CharIterator iterator(char[] array) { @@ -279,6 +319,11 @@ public abstract class ArrayIterator implements Iterator, JetObject { public TypeInfo getTypeInfo() { return typeInfo; } + + @Override + public JetObject getOuterObject() { + return null; + } } public static BooleanIterator iterator(boolean[] array) { diff --git a/stdlib/src/jet/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java index a999ce2f298..edc2199a870 100644 --- a/stdlib/src/jet/typeinfo/JetMethod.java +++ b/stdlib/src/jet/typeinfo/JetMethod.java @@ -11,6 +11,8 @@ import java.lang.annotation.Target; * The fact of receiver presence must be deducted from presence of 'this$receiver' parameter * * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) diff --git a/stdlib/src/jet/typeinfo/JetSignature.java b/stdlib/src/jet/typeinfo/JetSignature.java index ab2455903c2..fe43b49b50d 100644 --- a/stdlib/src/jet/typeinfo/JetSignature.java +++ b/stdlib/src/jet/typeinfo/JetSignature.java @@ -7,6 +7,8 @@ import java.util.*; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Retention(RetentionPolicy.RUNTIME) @interface JetSignature { diff --git a/stdlib/src/jet/typeinfo/JetTypeDescriptor.java b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java index 9d289c97b41..3e2b558ff8f 100644 --- a/stdlib/src/jet/typeinfo/JetTypeDescriptor.java +++ b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java @@ -2,6 +2,8 @@ package jet.typeinfo; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ public @interface JetTypeDescriptor{ // diff --git a/stdlib/src/jet/typeinfo/JetTypeParameter.java b/stdlib/src/jet/typeinfo/JetTypeParameter.java index b57809b98e5..2a748ce97bd 100644 --- a/stdlib/src/jet/typeinfo/JetTypeParameter.java +++ b/stdlib/src/jet/typeinfo/JetTypeParameter.java @@ -9,6 +9,8 @@ import java.lang.annotation.Target; * Annotation for parameters * * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) diff --git a/stdlib/src/jet/typeinfo/JetTypeProjection.java b/stdlib/src/jet/typeinfo/JetTypeProjection.java index 3605c0640e6..fbd90bf7739 100644 --- a/stdlib/src/jet/typeinfo/JetTypeProjection.java +++ b/stdlib/src/jet/typeinfo/JetTypeProjection.java @@ -5,6 +5,8 @@ import java.lang.annotation.RetentionPolicy; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Retention(RetentionPolicy.RUNTIME) public @interface JetTypeProjection { diff --git a/stdlib/src/jet/typeinfo/JetParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java similarity index 86% rename from stdlib/src/jet/typeinfo/JetParameter.java rename to stdlib/src/jet/typeinfo/JetValueParameter.java index bae06e264b1..3a0a2992ad4 100644 --- a/stdlib/src/jet/typeinfo/JetParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -9,10 +9,12 @@ import java.lang.annotation.Target; * Annotation for parameters * * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) -public @interface JetParameter { +public @interface JetValueParameter { /** * @return name of parameter */ diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 2fb20baa47e..a5ad5850ebe 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -79,14 +79,6 @@ public abstract class TypeInfo implements JetObject { return new TypeInfoImpl(klazz, nullable); } - public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfo outerTypeInfo) { - return new TypeInfoImpl(klazz, nullable, outerTypeInfo); - } - - public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfo outerTypeInfo, TypeInfoProjection[] projections) { - return new TypeInfoImpl(klazz, nullable, outerTypeInfo, projections); - } - public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfoProjection[] projections) { return new TypeInfoImpl(klazz, nullable, projections); } @@ -99,15 +91,13 @@ public abstract class TypeInfo implements JetObject { public abstract int getProjectionCount(); - public abstract TypeInfo getOuterTypeInfo(); - public abstract TypeInfoProjection getProjection(int index); public abstract TypeInfo getArgumentType(Class klass, int index); protected abstract TypeInfo substitute(List myVars); - protected abstract TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] projections); + protected abstract TypeInfo substitute(TypeInfoProjection[] projections); private static class TypeInfoVar extends TypeInfo { final int varIndex; @@ -151,11 +141,6 @@ public abstract class TypeInfo implements JetObject { return 0; } - @Override - public TypeInfo getOuterTypeInfo() { - return null; - } - @Override public TypeInfoProjection getProjection(int index) { throw new UnsupportedOperationException("Abstract TypeInfo"); @@ -172,7 +157,7 @@ public abstract class TypeInfo implements JetObject { } @Override - protected TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] projections) { + protected TypeInfo substitute(TypeInfoProjection[] projections) { return projections[varIndex].getType(); } @@ -181,6 +166,11 @@ public abstract class TypeInfo implements JetObject { throw new UnsupportedOperationException("Abstract TypeInfo"); } + @Override + public JetObject getOuterObject() { + return null; + } + @Override public String toString() { return "T:" + signature.klazz.getName() + ":" + varIndex; @@ -192,22 +182,12 @@ public abstract class TypeInfo implements JetObject { private final Signature signature; private final boolean nullable; private final TypeInfoProjection[] projections; - private final TypeInfo outerTypeInfo; private TypeInfoImpl(Class theClass, boolean nullable) { - this(theClass, nullable, null, EMPTY); - } - - private TypeInfoImpl(Class theClass, boolean nullable, TypeInfo outerTypeInfo) { - this(theClass, nullable, outerTypeInfo, EMPTY); + this(theClass, nullable, EMPTY); } private TypeInfoImpl(Class theClass, boolean nullable, TypeInfoProjection[] projections) { - this(theClass, nullable, null, projections); - } - - private TypeInfoImpl(Class theClass, boolean nullable, TypeInfo outerTypeInfo, TypeInfoProjection[] projections) { - this.outerTypeInfo = outerTypeInfo; this.signature = Parser.parse(theClass); this.nullable = nullable; this.projections = projections; @@ -247,7 +227,7 @@ public abstract class TypeInfo implements JetObject { if(klass == this.signature.klazz) return projections[index].getType(); else { - return getSuperTypeInfo(klass).substitute(outerTypeInfo, projections).getArgumentType(klass, index); + return getSuperTypeInfo(klass).substitute(projections).getArgumentType(klass, index); } } @@ -283,14 +263,14 @@ public abstract class TypeInfo implements JetObject { } @Override - protected TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] prj) { + protected TypeInfo substitute(TypeInfoProjection[] prj) { if(projections.length == 0) return new TypeInfoImpl(signature.klazz, nullable, EMPTY); else { TypeInfoProjection [] proj = new TypeInfoProjection[projections.length]; for(int i = 0; i != proj.length; ++i) { final int finalI = i; - final TypeInfo substitute = projections[finalI].getType().substitute(outer, prj); + final TypeInfo substitute = projections[finalI].getType().substitute(prj); proj[i] = new TypeInfoProjection(){ @Override @@ -359,11 +339,6 @@ public abstract class TypeInfo implements JetObject { return projections.length; } - @Override - public TypeInfo getOuterTypeInfo() { - return outerTypeInfo; - } - @Override public final String toString() { StringBuilder sb = new StringBuilder().append(signature.klazz.getName()); @@ -388,6 +363,11 @@ public abstract class TypeInfo implements JetObject { return typeInfo; } + @Override + public JetObject getOuterObject() { + return null; + } + public final boolean isSubtypeOf(TypeInfoImpl superType) { if (nullable && !superType.nullable) { return false; @@ -410,7 +390,6 @@ public abstract class TypeInfo implements JetObject { } public static class Signature { - final Signature outer; final Class klazz; List variables; @@ -419,8 +398,7 @@ public abstract class TypeInfo implements JetObject { final HashMap superSignatures = new HashMap(); - public Signature(Signature outer, Class klazz) { - this.outer = outer; + public Signature(Class klazz) { this.klazz = klazz; } @@ -502,7 +480,7 @@ public abstract class TypeInfo implements JetObject { if(value != null) { Parser parser = new Parser(value, klass.getClassLoader()); Class enclosingClass = klass.getEnclosingClass(); - Signature signature = new Signature(parse(enclosingClass), klass); + Signature signature = new Signature(klass); map.put(klass, signature); parser.parseVars(signature); parser.parseTypes(signature); @@ -517,7 +495,7 @@ public abstract class TypeInfo implements JetObject { // todo complete impl java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass(); - Signature signature = new Signature(parse(klass.getEnclosingClass()), klass); + Signature signature = new Signature(klass); TypeVariable[] typeParameters = klass.getTypeParameters(); if(typeParameters == null || typeParameters.length == 0) { @@ -682,14 +660,14 @@ public abstract class TypeInfo implements JetObject { if(klazz.equals(signature.klazz.getName())) return new TypeInfoVar(signature, nullable, signature.varNames.get(name)); else { - Signature sig = signature; - while(!klazz.equals(sig.klazz.getName())) { - sig = sig.outer; - if(sig == null) - throw new IllegalStateException(); - } +// Signature sig = signature; +// while(!klazz.equals(sig.klazz.getName())) { +// sig = sig.outer; +// if(sig == null) +// throw new IllegalStateException(); +// } - return new TypeInfoVar(sig, nullable, sig.varNames.get(name)); + throw new UnsupportedOperationException("outer type info does not supported"); } } @@ -716,7 +694,7 @@ public abstract class TypeInfo implements JetObject { private static class ArraySignature extends Signature { public ArraySignature(Class klass) { - super(null, klass); + super(klass); variables = new LinkedList(); varNames = new HashMap(); varNames.put("T", 0);