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..ab2d5de350d --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -0,0 +1,339 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureAdapter; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureWriter; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; +import org.objectweb.asm.util.CheckSignatureAdapter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @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 enum State { + START, + TYPE_PARAMETERS, + + PARAMETERS, + RETURN_TYPE, + METHOD_END, + + SUPERS, + CLASS_END, + } + + private final SignatureWriter signatureWriter = new SignatureWriter(); + private final SignatureVisitor signatureVisitor; + + private JetSignatureWriter jetSignatureWriter; + + private String kotlinClassSignature; + + private List kotlinParameterTypes = new ArrayList(); + private String kotlinReturnType; + + private final Mode mode; + private State state = State.START; + + public BothSignatureWriter(Mode mode) { + this.mode = mode; + 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(); + } + } + } + + private void checkState(State state) { + if (DEBUG_SIGNATURE_WRITER) { + if (state != this.state) { + throw new IllegalStateException(); + } + if (jetSignatureWriter != null) { + throw new IllegalStateException(); + } + checkTopLevel(); + } + } + + private void transitionState(State from, State to) { + checkState(from); + state = to; + } + + + /** + * Shortcut + */ + public void writeAsmType(Type asmType, boolean nullable) { + switch (asmType.getSort()) { + case Type.OBJECT: + writeClassBegin(asmType.getInternalName(), nullable); + writeClassEnd(); + return; + case Type.ARRAY: + writeArrayType(nullable); + writeAsmType(asmType.getElementType(), false); + writeArrayEnd(); + return; + default: + String descriptor = asmType.getDescriptor(); + if (descriptor.length() != 1) { + throw new IllegalStateException(); + } + writeBaseType(descriptor.charAt(0), nullable); + } + } + + private void writeBaseType(char c, boolean nullable) { + if (nullable) { + throw new IllegalStateException(); + } + signatureVisitor().visitBaseType(c); + jetSignatureWriter.visitBaseType(c, nullable); + } + + public void writeClassBegin(String internalName, boolean nullable) { + signatureVisitor().visitClassType(internalName); + jetSignatureWriter.visitClassType(internalName, nullable); + } + + public void writeClassEnd() { + signatureVisitor().visitEnd(); + jetSignatureWriter.visitEnd(); + } + + public void writeArrayType(boolean nullable) { + push(signatureVisitor().visitArrayType()); + jetSignatureWriter.visitArrayType(nullable); + } + + public void writeArrayEnd() { + pop(); + } + + public void writeTypeArgument(char c) { + push(signatureVisitor().visitTypeArgument(c)); + jetSignatureWriter.visitTypeArgument(c); + } + + public void writeTypeArgumentEnd() { + pop(); + } + + public void writeTypeVariable(final String name, boolean nullable) { + signatureVisitor().visitTypeVariable(name); + jetSignatureWriter.visitTypeVariable(name, nullable); + } + + public void writeFormalTypeParameter(final String name) { + checkTopLevel(); + + signatureVisitor().visitFormalTypeParameter(name); + jetSignatureWriter.visitFormalTypeParameter(name); + } + + public void writerFormalTypeParametersStart() { + checkTopLevel(); + transitionState(State.START, State.TYPE_PARAMETERS); + jetSignatureWriter = new JetSignatureWriter(); + } + + public void writeFormalTypeParametersEnd() { + jetSignatureWriter = null; + checkState(State.TYPE_PARAMETERS); + } + + public void writeClassBound() { + push(signatureVisitor().visitClassBound()); + jetSignatureWriter.visitClassBound(); + } + + public void writeClassBoundEnd() { + pop(); + } + + public void writeInterfaceBound() { + push(signatureVisitor().visitInterfaceBound()); + jetSignatureWriter.visitInterfaceBound(); + } + + public void writeInterfaceBoundEnd() { + pop(); + } + + public void writeParametersStart() { + transitionState(State.TYPE_PARAMETERS, State.PARAMETERS); + } + + public void writeParametersEnd() { + checkState(State.PARAMETERS); + } + + public void writeParameterType() { + push(signatureVisitor().visitParameterType()); + jetSignatureWriter = new JetSignatureWriter(); + //jetSignatureWriter.visitParameterType(); + } + + public void writeParameterTypeEnd() { + pop(); + String signature = jetSignatureWriter.toString(); + kotlinParameterTypes.add(signature); + + if (DEBUG_SIGNATURE_WRITER) { + new JetSignatureReader(signature).acceptTypeOnly(new JetSignatureAdapter()); + } + + jetSignatureWriter = null; + } + + public void writeReturnType() { + transitionState(State.PARAMETERS, State.RETURN_TYPE); + + jetSignatureWriter = new JetSignatureWriter(); + + push(signatureVisitor().visitReturnType()); + //jetSignatureWriter.visitReturnType(); + } + + public void writeReturnTypeEnd() { + pop(); + + kotlinReturnType = jetSignatureWriter.toString(); + + if (DEBUG_SIGNATURE_WRITER) { + new JetSignatureReader(kotlinReturnType).acceptTypeOnly(new JetSignatureAdapter()); + } + + jetSignatureWriter = null; + transitionState(State.RETURN_TYPE, State.METHOD_END); + } + + public void writeSupersStart() { + transitionState(State.TYPE_PARAMETERS, State.SUPERS); + jetSignatureWriter = new JetSignatureWriter(); + } + + public void writeSupersEnd() { + kotlinClassSignature = jetSignatureWriter.toString(); + jetSignatureWriter = null; + transitionState(State.SUPERS, State.CLASS_END); + } + + public void writeSuperclass() { + push(signatureVisitor().visitSuperclass()); + jetSignatureWriter.visitSuperclass(); + } + + public void writeSuperclassEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + public void writeInterface() { + checkTopLevel(); + checkMode(Mode.CLASS); + + push(signatureVisitor().visitInterface()); + jetSignatureWriter.visitInterface(); + } + + public void writeInterfaceEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + + + + @Nullable + public String makeJavaString() { + if (state != State.METHOD_END && state != State.CLASS_END) { + throw new IllegalStateException(); + } + checkTopLevel(); + // TODO: return null if not generic + return signatureWriter.toString(); + } + + @NotNull + public List makeKotlinSignatures() { + checkState(State.METHOD_END); + // TODO: return nulls if equal to #makeJavaString + return kotlinParameterTypes; + } + + @Nullable + public String makeKotlinReturnTypeSignature() { + checkState(State.METHOD_END); + return kotlinReturnType; + } + + @Nullable + public String makeKotlinClassSignature() { + checkState(State.CLASS_END); + return kotlinClassSignature; + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 46bd9a3ad45..75e3d28323a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -53,7 +53,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { public static CallableMethod asCallableMethod(FunctionDescriptor fd) { Method descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); - final CallableMethod result = new CallableMethod(owner, new JvmMethodSignature(descriptor, null), INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + final CallableMethod result = new CallableMethod(owner, new JvmMethodSignature(descriptor, null, null, null), INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(fd); } @@ -165,7 +165,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); - fc.generateMethod(body, new JvmMethodSignature(invokeSignature(funDescriptor), null), funDescriptor); + fc.generateMethod(body, new JvmMethodSignature(invokeSignature(funDescriptor), null, null, null), funDescriptor); return closureContext.outerWasUsed; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b8628fbc7c0..4513595264f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2475,9 +2475,13 @@ If finally block is present, its last expression is the value of try expression. return hasTypeInfoForInstanceOf(type.getArguments().get(0).getType()); } - for(TypeParameterDescriptor proj : classDescriptor.getTypeConstructor().getParameters()) { - if(proj.isReified()) { - return true; + for (int i = 0; i < type.getArguments().size(); i++) { + TypeParameterDescriptor typeParameterDescriptor = classDescriptor.getTypeConstructor().getParameters().get(i); + if(typeParameterDescriptor.isReified()) { + TypeProjection typeProjection = type.getArguments().get(i); + if( !typeProjection.getType().equals(typeParameterDescriptor.getUpperBoundsAsType())) { + return true; + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 4edd7db34a4..27cea25ce10 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; @@ -90,19 +90,22 @@ public class FunctionCodegen { if(functionDescriptor.getReturnType().isNullable()) { av.visit(StdlibNames.JET_METHOD_NULLABLE_RETURN_TYPE_FIELD, true); } + if (jvmSignature.getKotlinReturnType() != null) { + av.visit(StdlibNames.JET_METHOD_RETURN_TYPE_FIELD, jvmSignature.getKotlinReturnType()); + } av.visitEnd(); } 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 +115,17 @@ 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); + } + if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) { + av.visit(StdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD, jvmSignature.getKotlinParameterTypes().get(i)); } av.visitEnd(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 0af0a1ef2e8..cd89380cbf5 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(JetTypeMapper.TYPE_JET_OBJECT.getInternalName()); - 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.getJavaGenericSignature(), + signature.getSuperclassName(), + signature.getInterfaces().toArray(new String[0]) ); v.visitSource(myClass.getContainingFile().getName(), null); @@ -95,29 +78,54 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - @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); + private JvmClassSignature signature() { + List superInterfaces; + + LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); + + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + + + { // type parameters + List typeParameters = descriptor.getTypeConstructor().getParameters(); + typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); } - SignatureVisitor superclassSignatureVisitor = signatureVisitor.visitSuperclass(); - // TODO: wrong - superclassSignatureVisitor.visitClassType("java/lang/Object"); - // TODO: add interfaces - superclassSignatureVisitor.visitEnd(); + + signatureVisitor.writeSupersStart(); - // TODO: return null if class is not generic and does not have generic superclasses + { // superclass + signatureVisitor.writeSuperclass(); + if (superClassType == null) { + signatureVisitor.writeClassBegin(superClass, false); + signatureVisitor.writeClassEnd(); + } else { + typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + } + signatureVisitor.writeSuperclassEnd(); + } - return signatureWriter.toString(); + + { // superinterfaces + superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.isInterface(superClassDescriptor)) { + signatureVisitor.writeInterface(); + Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + signatureVisitor.writeInterfaceEnd(); + superInterfacesLinkedHashSet.add(jvmName.getInternalName()); + } + } + + superInterfaces = new ArrayList(superInterfacesLinkedHashSet); + } + + signatureVisitor.writeSupersEnd(); + + return new JvmClassSignature(jvmName(), superClass, superInterfaces, signatureVisitor.makeJavaString(), signatureVisitor.makeKotlinClassSignature()); } private String jvmName() { @@ -125,6 +133,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 +147,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; } @@ -310,7 +322,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } constructorMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - callableMethod = new CallableMethod("", new JvmMethodSignature(constructorMethod, null) /* TODO */, Opcodes.INVOKESPECIAL, Collections.emptyList()); + callableMethod = new CallableMethod("", new JvmMethodSignature(constructorMethod, null, null, null) /* TODO */, Opcodes.INVOKESPECIAL, Collections.emptyList()); } else { callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 7fa09823a80..58a60e131b6 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,7 +54,7 @@ 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/JetParameter"); + 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"); @@ -165,16 +162,16 @@ 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, false); } return Type.VOID_TYPE; } if (jetType.equals(JetStandardClasses.getNullableNothingType())) { if (signatureVisitor != null) { - visitAsmType(signatureVisitor, TYPE_OBJECT); + visitAsmType(signatureVisitor, TYPE_OBJECT, false); } return TYPE_OBJECT; } @@ -226,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); } @@ -237,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"); @@ -255,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(jetType.isNullable()); + mapType(memberType, kind, signatureVisitor, true); + signatureVisitor.writeArrayEnd(); } if (!isGenericsArray(jetType)) { @@ -268,7 +271,7 @@ public class JetTypeMapper { if (JetStandardClasses.getAny().equals(descriptor)) { if (signatureVisitor != null) { - visitAsmType(signatureVisitor, TYPE_OBJECT); + visitAsmType(signatureVisitor, TYPE_OBJECT, jetType.isNullable()); } return TYPE_OBJECT; } @@ -279,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(), jetType.isNullable()); 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; @@ -294,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(), jetType.isNullable()); } return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); @@ -303,34 +307,19 @@ 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)); + visitAsmType(signatureVisitor, boxType(asmType), jetType.isNullable()); } else { - visitAsmType(signatureVisitor, asmType); + visitAsmType(signatureVisitor, asmType, jetType.isNullable()); } } 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, boolean nullable) { + visitor.writeAsmType(asmType, nullable); } public static Type unboxType(final Type type) { @@ -386,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; @@ -451,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(); @@ -484,24 +461,114 @@ 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(); + } } + if (signatureVisitor != null) { + signatureVisitor.writeParametersStart(); + } + 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, false); + 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); + + if (signatureVisitor != null) { + signatureVisitor.writeParametersEnd(); + } + + Type returnType; + if (f instanceof ConstructorDescriptor) { + returnType = Type.VOID_TYPE; + if (signatureVisitor != null) { + signatureVisitor.writeReturnType(); + visitAsmType(signatureVisitor, Type.VOID_TYPE, false); + 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); + if (signatureVisitor == null) { + return new JvmMethodSignature(method, null, null, null); + } else { + return new JvmMethodSignature(method, signatureVisitor.makeJavaString(), + signatureVisitor.makeKotlinSignatures(), signatureVisitor.makeKotlinReturnTypeSignature()); + } + } + + + public void writeFormalTypeParameters(List typeParameters, BothSignatureWriter signatureVisitor) { + if (signatureVisitor == null) { + return; + } + + signatureVisitor.writerFormalTypeParametersStart(); + for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); + } + signatureVisitor.writeFormalTypeParametersEnd(); + } + + 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) { @@ -516,7 +583,7 @@ public class JetTypeMapper { } Type returnType = mapReturnType(f.getReturnType()); // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])), null); + return new JvmMethodSignature(new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])), null, null, null); } @@ -541,7 +608,7 @@ public class JetTypeMapper { } // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, returnType, params.toArray(new Type[params.size()])), null); + return new JvmMethodSignature(new Method(name, returnType, params.toArray(new Type[params.size()])), null, null, null); } @Nullable @@ -571,7 +638,7 @@ public class JetTypeMapper { params.add(mapType(inType)); // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, Type.VOID_TYPE, params.toArray(new Type[params.size()])), null); + return new JvmMethodSignature(new Method(name, Type.VOID_TYPE, params.toArray(new Type[params.size()])), null, null, null); } private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, List valueParameterTypes) { @@ -593,7 +660,7 @@ public class JetTypeMapper { } Method method = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, null); // TODO: generics signature + return new JvmMethodSignature(method, null, null, null); // TODO: generics signature } public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java new file mode 100644 index 00000000000..4eeeaf10542 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java @@ -0,0 +1,46 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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 javaGenericSignature; + private final String kotlinGenericSignature; + + public JvmClassSignature(String name, String superclassName, List interfaces, + @Nullable String javaGenericSignature, @Nullable String kotlinGenericSignature) { + this.name = name; + this.superclassName = superclassName; + this.interfaces = interfaces; + this.javaGenericSignature = javaGenericSignature; + this.kotlinGenericSignature = kotlinGenericSignature; + } + + public String getName() { + return name; + } + + public String getSuperclassName() { + return superclassName; + } + + public List getInterfaces() { + return interfaces; + } + + public String getJavaGenericSignature() { + return javaGenericSignature; + } + + public String getKotlinGenericSignature() { + return kotlinGenericSignature; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java index 2dd2395c4fd..6eda7035501 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java @@ -4,6 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.commons.Method; +import java.util.List; + /** * @author Stepan Koltsov */ @@ -12,10 +14,16 @@ public class JvmMethodSignature { private final Method asmMethod; /** Null when we don't care about type parameters */ private final String genericsSignature; + // TODO: type parameters + private final List kotlinParameterTypes; + private final String kotlinReturnType; - public JvmMethodSignature(@NotNull Method asmMethod, @Nullable String genericsSignature) { + public JvmMethodSignature(@NotNull Method asmMethod, @Nullable String genericsSignature, + @Nullable List kotlinParameterTypes, @Nullable String kotlinReturnType) { this.asmMethod = asmMethod; this.genericsSignature = genericsSignature; + this.kotlinParameterTypes = kotlinParameterTypes; + this.kotlinReturnType = kotlinReturnType; } public Method getAsmMethod() { @@ -25,4 +33,12 @@ public class JvmMethodSignature { public String getGenericsSignature() { return genericsSignature; } + + public List getKotlinParameterTypes() { + return kotlinParameterTypes; + } + + public String getKotlinReturnType() { + return kotlinReturnType; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 9a6f2c5210a..5e8b92a7849 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -2,6 +2,7 @@ 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; @@ -43,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); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java index b8ee1a1c445..2903242169c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java @@ -68,6 +68,10 @@ public class SignatureUtil { private static void genTypeParams(JetClass type, StringBuilder sb) { List parameters = type.getTypeParameterList().getParameters(); + if (parameters.isEmpty()) { + return; + } + sb.append('<'); for(JetTypeParameter param : parameters) { sb.append("T"); Variance variance = param.getVariance(); @@ -78,5 +82,6 @@ public class SignatureUtil { sb.append(param.getName()); sb.append(";"); } + sb.append('>'); } } 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..b70626a96a7 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -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; @@ -361,6 +360,7 @@ public class JavaDescriptorResolver { boolean changeNullable = false; boolean nullable = true; + String typeFromAnnotation = null; // TODO: must be very slow, make it lazy? String name = parameter.getName() != null ? parameter.getName() : "p" + i; @@ -370,13 +370,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 { @@ -384,10 +384,20 @@ public class JavaDescriptorResolver { nullable = false; changeNullable = true; } + + PsiLiteralExpression signatureExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD); + if (signatureExpression != null) { + typeFromAnnotation = (String) signatureExpression.getValue(); + } } } - JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); + JetType outType; + if (typeFromAnnotation != null) { + outType = semanticServices.getTypeTransformer().transformToType(typeFromAnnotation); + } else { + outType = semanticServices.getTypeTransformer().transformToType(psiType); + } return new ValueParameterDescriptorImpl( containingDeclaration, i, @@ -510,6 +520,8 @@ public class JavaDescriptorResolver { private JetType makeReturnType(PsiType returnType, PsiMethod method) { boolean changeNullable = false; boolean nullable = true; + + String returnTypeFromAnnotation = null; for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) { if (annotation.getQualifiedName().equals(StdlibNames.JET_METHOD_CLASS)) { @@ -521,9 +533,19 @@ public class JavaDescriptorResolver { nullable = false; changeNullable = true; } + + PsiLiteralExpression returnTypeExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_METHOD_RETURN_TYPE_FIELD); + if (returnTypeExpression != null) { + returnTypeFromAnnotation = (String) returnTypeExpression.getValue(); + } } } - JetType transformedType = semanticServices.getTypeTransformer().transformToType(returnType); + JetType transformedType; + if (returnTypeFromAnnotation != null) { + transformedType = semanticServices.getTypeTransformer().transformToType(returnTypeFromAnnotation); + } else { + transformedType = semanticServices.getTypeTransformer().transformToType(returnType); + } if (changeNullable) { return TypeUtils.makeNullableAsSpecified(transformedType, nullable); } else { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java index 8c82fd11367..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 @@ -77,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()) { @@ -84,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/JavaTypeTransformer.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java index 3f19264e915..82d25433ac1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -6,6 +6,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor; import org.jetbrains.jet.lang.types.*; import java.util.Collections; @@ -57,6 +59,19 @@ public class JavaTypeTransformer { return result; } + @NotNull + public JetType transformToType(@NotNull String kotlinSignature) { + final JetType[] r = new JetType[1]; + JetTypeJetSignatureReader reader = new JetTypeJetSignatureReader(resolver, standardLibrary) { + @Override + protected void done(@NotNull JetType jetType) { + r[0] = jetType; + } + }; + new JetSignatureReader(kotlinSignature).acceptType(reader); + return r[0]; + } + @NotNull public JetType transformToType(@NotNull PsiType javaType) { return javaType.accept(new PsiTypeVisitor() { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java new file mode 100644 index 00000000000..0e0819d8f7a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java @@ -0,0 +1,196 @@ +package org.jetbrains.jet.lang.resolve.java; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader; +import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.JetTypeImpl; +import org.jetbrains.jet.lang.types.TypeProjection; +import org.jetbrains.jet.lang.types.Variance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author Stepan Koltsov + */ +public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor { + + private final JavaDescriptorResolver javaDescriptorResolver; + private final JetStandardLibrary jetStandardLibrary; + + public JetTypeJetSignatureReader(JavaDescriptorResolver javaDescriptorResolver, JetStandardLibrary jetStandardLibrary) { + this.javaDescriptorResolver = javaDescriptorResolver; + this.jetStandardLibrary = jetStandardLibrary; + } + + + + @Override + public void visitFormalTypeParameter(String name) { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitClassBound() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitInterfaceBound() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitSuperclass() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitInterface() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitParameterType() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitReturnType() { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitExceptionType() { + throw new IllegalStateException(); + } + + private JetType getPrimitiveType(char descriptor, boolean nullable) { + if (!nullable) { + switch (descriptor) { + case 'Z': + return jetStandardLibrary.getBooleanType(); + case 'C': + return jetStandardLibrary.getCharType(); + case 'B': + return jetStandardLibrary.getByteType(); + case 'S': + return jetStandardLibrary.getShortType(); + case 'I': + return jetStandardLibrary.getIntType(); + case 'F': + return jetStandardLibrary.getFloatType(); + case 'J': + return jetStandardLibrary.getLongType(); + case 'D': + return jetStandardLibrary.getDoubleType(); + case 'V': + return JetStandardClasses.getUnitType(); + } + } else { + switch (descriptor) { + case 'Z': + return jetStandardLibrary.getNullableBooleanType(); + case 'C': + return jetStandardLibrary.getNullableCharType(); + case 'B': + return jetStandardLibrary.getNullableByteType(); + case 'S': + return jetStandardLibrary.getNullableShortType(); + case 'I': + return jetStandardLibrary.getNullableIntType(); + case 'F': + return jetStandardLibrary.getNullableFloatType(); + case 'J': + return jetStandardLibrary.getNullableLongType(); + case 'D': + return jetStandardLibrary.getNullableDoubleType(); + case 'V': + throw new IllegalStateException("incorrect signature: nullable void"); + } + } + throw new IllegalStateException("incorrect signature"); + } + + @Override + public void visitBaseType(char descriptor, boolean nullable) { + done(getPrimitiveType(descriptor, nullable)); + } + + @Override + public void visitTypeVariable(String name, boolean nullable) { + throw new IllegalStateException(); + } + + @Override + public JetSignatureVisitor visitArrayType(boolean nullable) { + throw new IllegalStateException(); + } + + + private ClassDescriptor classDescriptor; + private boolean nullable; + private List typeArguments; + + @Override + public void visitClassType(String name, boolean nullable) { + String ourName = name.replace('/', '.'); + this.classDescriptor = javaDescriptorResolver.resolveClass(ourName); + if (this.classDescriptor == null) { + throw new IllegalStateException("class not found by name: " + ourName); // TODO: wrong exception + } + this.nullable = nullable; + this.typeArguments = new ArrayList(); + } + + @Override + public void visitInnerClassType(String name, boolean nullable) { + throw new IllegalStateException(); + } + + @Override + public void visitTypeArgument() { + throw new IllegalStateException(); + } + + private static Variance parseVariance(char wildcard) { + switch (wildcard) { + case '=': return Variance.INVARIANT; + case '+': return Variance.OUT_VARIANCE; + case '-': return Variance.IN_VARIANCE; + default: throw new IllegalStateException(); + } + } + + @Override + public JetSignatureVisitor visitTypeArgument(final char wildcard) { + return new JetTypeJetSignatureReader(javaDescriptorResolver, jetStandardLibrary) { + + @Override + protected void done(@NotNull JetType jetType) { + typeArguments.add(new TypeProjection(parseVariance(wildcard), jetType)); + } + }; + } + + @Override + public void visitEnd() { + JetType jetType = new JetTypeImpl( + Collections.emptyList(), + classDescriptor.getTypeConstructor(), + nullable, + typeArguments, + ErrorUtils.getErrorScope()); + done(jetType); + } + + protected abstract void done(@NotNull JetType jetType); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java similarity index 53% rename from compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java index 5bade930733..c6223502385 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.lang.resolve; +package org.jetbrains.jet.lang.resolve.java; import org.objectweb.asm.Type; @@ -7,12 +7,13 @@ import org.objectweb.asm.Type; */ public class StdlibNames { - 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_VALUE_PARAMETER_CLASS = "jet.typeinfo.JetValueParameter"; + public static final String JET_VALUE_PARAMETER_DESCRIPTOR = "Ljet/typeinfo/JetValueParameter;"; - 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 String JET_VALUE_PARAMETER_NAME_FIELD = "name"; + public static final String JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue"; + public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable"; + public static final String JET_VALUE_PARAMETER_TYPE_FIELD = "type"; public static final String JET_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter"; @@ -25,8 +26,10 @@ public class StdlibNames { public static final String JET_METHOD_DESCRIPTOR = "Ljet/typeinfo/JetMethod;"; public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; + public static final String JET_METHOD_RETURN_TYPE_FIELD = "returnType"; + public static final String JET_OBJECT_INTERNAL = "jet/JetObject"; public static final String JET_OBJECT_CLASS = "jet.JetObject"; public static final String JET_OBJECT_DESCRIPTOR = "Ljet/JetObject;"; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java new file mode 100644 index 00000000000..5f9d10245b0 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java @@ -0,0 +1,79 @@ +package org.jetbrains.jet.lang.resolve.java.signature; + +/** + * @author Stepan Koltsov + */ +public class JetSignatureAdapter implements JetSignatureVisitor { + @Override + public void visitFormalTypeParameter(String name) { + } + + @Override + public JetSignatureVisitor visitClassBound() { + return this; + } + + @Override + public JetSignatureVisitor visitInterfaceBound() { + return this; + } + + @Override + public JetSignatureVisitor visitSuperclass() { + return this; + } + + @Override + public JetSignatureVisitor visitInterface() { + return this; + } + + @Override + public JetSignatureVisitor visitParameterType() { + return this; + } + + @Override + public JetSignatureVisitor visitReturnType() { + return this; + } + + @Override + public JetSignatureVisitor visitExceptionType() { + return this; + } + + @Override + public void visitBaseType(char descriptor, boolean nullable) { + } + + @Override + public void visitTypeVariable(String name, boolean nullable) { + } + + @Override + public JetSignatureVisitor visitArrayType(boolean nullable) { + return this; + } + + @Override + public void visitClassType(String name, boolean nullable) { + } + + @Override + public void visitInnerClassType(String name, boolean nullable) { + } + + @Override + public void visitTypeArgument() { + } + + @Override + public JetSignatureVisitor visitTypeArgument(char wildcard) { + return this; + } + + @Override + public void visitEnd() { + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java new file mode 100644 index 00000000000..cbdebb01b3a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java @@ -0,0 +1,172 @@ +package org.jetbrains.jet.lang.resolve.java.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()); + } + } + } + + public int acceptType(JetSignatureVisitor v) { + return parseType(this.signature, 0, v); + } + + public void acceptTypeOnly(JetSignatureVisitor v) { + int r = acceptType(v); + if (r != signature.length()) { + throw new IllegalStateException(); + } + } + + + private static int parseType( + final String signature, + 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/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java new file mode 100644 index 00000000000..e353dd6dbb3 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java @@ -0,0 +1,141 @@ +package org.jetbrains.jet.lang.resolve.java.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/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java new file mode 100644 index 00000000000..7e1a7837a08 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java @@ -0,0 +1,201 @@ +package org.jetbrains.jet.lang.resolve.java.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/src/jet/Library.jet b/compiler/frontend/src/jet/Library.jet index 888934c7121..580d1dd1a2b 100644 --- a/compiler/frontend/src/jet/Library.jet +++ b/compiler/frontend/src/jet/Library.jet @@ -198,6 +198,10 @@ trait Hashable { class Boolean : Comparable { fun not() : Boolean + fun and(other : Boolean) : Boolean + + fun or(other : Boolean) : Boolean + fun xor(other : Boolean) : Boolean fun equals(other : Any?) : Boolean diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 1ead3251e54..c3dab813a27 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -577,7 +577,7 @@ public class JetControlFlowProcessor { JetExpression defaultValue = parameter.getDefaultValue(); builder.declare(parameter); if (defaultValue != null) { - builder.read(defaultValue); + value(defaultValue, inCondition); } builder.write(parameter, parameter); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 1485bb0056b..03199499b0a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -232,6 +232,14 @@ public interface Errors { ParameterizedDiagnosticFactory1 RETURN_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "This function must return a value of type {0}"); ParameterizedDiagnosticFactory1 EXPECTED_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}"); ParameterizedDiagnosticFactory1 ASSIGNMENT_TYPE_MISMATCH = ParameterizedDiagnosticFactory1.create(ERROR, "Expected a value of type {0}. Assignment operation is not an expression, so it does not return any value"); + ParameterizedDiagnosticFactory1 IMPLICIT_CAST_TO_UNIT_OR_ANY = ParameterizedDiagnosticFactory1.create(WARNING, "Type was casted to ''{0}''. Please specify ''{0}'' as expected type, if you mean such cast"); + ParameterizedDiagnosticFactory1 EXPRESSION_EXPECTED = new ParameterizedDiagnosticFactory1(ERROR, "{0} is not an expression, and only expression are allowed here") { + @Override + protected String makeMessageFor(JetExpression expression) { + String expressionType = expression.toString(); + return expressionType.substring(0, 1) + expressionType.substring(1).toLowerCase(); + } + }; ParameterizedDiagnosticFactory1 UPPER_BOUND_VIOLATED = ParameterizedDiagnosticFactory1.create(ERROR, "An upper bound {0} is violated"); // TODO : Message ParameterizedDiagnosticFactory1 FINAL_CLASS_OBJECT_UPPER_BOUND = ParameterizedDiagnosticFactory1.create(ERROR, "{0} is a final type, and thus a class object cannot extend it"); 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/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java index 89a95abcd27..c5df77d3682 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; @@ -449,8 +450,8 @@ public class DescriptorResolver { } @NotNull - public VariableDescriptor resolveLocalVariableDescriptor(DeclarationDescriptor containingDeclaration, JetScope scope, JetProperty property) { - JetType type = getVariableType(scope, property, false); // For a local variable the type must not be deferred + public VariableDescriptor resolveLocalVariableDescriptor(DeclarationDescriptor containingDeclaration, JetScope scope, JetProperty property, DataFlowInfo dataFlowInfo) { + JetType type = getVariableType(scope, property, dataFlowInfo, false); // For a local variable the type must not be deferred return resolveLocalVariableDescriptorWithType(containingDeclaration, property, type); } @@ -548,9 +549,9 @@ public class DescriptorResolver { ? ReceiverDescriptor.NO_RECEIVER : new ExtensionReceiver(propertyDescriptor, receiverType); - JetScope scope2 = getPropertyDeclarationInnerScope(scope, propertyDescriptor, typeParameterDescriptors, receiverDescriptor); + JetScope propertyScope = getPropertyDeclarationInnerScope(scope, propertyDescriptor, typeParameterDescriptors, receiverDescriptor); - JetType type = getVariableType(scope2, property, true); + JetType type = getVariableType(propertyScope, property, DataFlowInfo.EMPTY, true); JetType inType = isVar ? type : null; propertyDescriptor.setType(inType, type, typeParameterDescriptors, DescriptorUtils.getExpectedThisObjectIfNeeded(containingDeclaration), receiverDescriptor); @@ -580,7 +581,7 @@ public class DescriptorResolver { } @NotNull - private JetType getVariableType(@NotNull final JetScope scope, @NotNull final JetProperty property, boolean allowDeferred) { + private JetType getVariableType(@NotNull final JetScope scope, @NotNull final JetProperty property, @NotNull final DataFlowInfo dataFlowInfo, boolean allowDeferred) { // TODO : receiver? JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); @@ -598,8 +599,7 @@ public class DescriptorResolver { LazyValue lazyValue = new LazyValueWithDefault(ErrorUtils.createErrorType("Recursive dependency")) { @Override protected JetType compute() { - //JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); - return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE); + return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo); } }; if (allowDeferred) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java index ee76f1ed2e9..2025559fc74 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -95,7 +95,7 @@ public class ErrorUtils { true, Collections.emptyList(), Collections.emptyList(), getErrorScope(), ERROR_CONSTRUCTOR_GROUP, ERROR_CONSTRUCTOR); } - private static JetScope getErrorScope() { + public static JetScope getErrorScope() { return ERROR_SCOPE; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index a6e120b1e8d..b795a4cea1e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -242,6 +242,11 @@ public class JetStandardClasses { public static JetType getAnyType() { return ANY_TYPE; } + + public static boolean isAny(JetType type) { + return !(type instanceof NamespaceType) && + type.getConstructor() == ANY_TYPE.getConstructor(); + } public static JetType getNullableAnyType() { return NULLABLE_ANY_TYPE; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java index 4e1fd0d08cd..c8bc340d8bb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeImpl.java @@ -21,7 +21,7 @@ public final class JetTypeImpl extends AnnotatedImpl implements JetType { private final boolean nullable; private JetScope memberScope; - public JetTypeImpl(List annotations, TypeConstructor constructor, boolean nullable, List arguments, JetScope memberScope) { + public JetTypeImpl(List annotations, TypeConstructor constructor, boolean nullable, @NotNull List arguments, JetScope memberScope) { super(annotations); this.constructor = constructor; this.nullable = nullable; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 2e3b5f83ede..6e6f3cfa7c9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -361,6 +361,7 @@ public class TypeUtils { fullSubstitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); } } + if (JetStandardClasses.isNothingOrNullableNothing(context)) return; for (JetType supertype : context.getConstructor().getSupertypes()) { fillInDeepSubstitutor(supertype, substitutor, substitution, fullSubstitution); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 8b58250041f..f3600ca8c13 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -110,11 +110,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context) { + return visitParenthesizedExpression(expression, context, false); + } + + public JetType visitParenthesizedExpression(JetParenthesizedExpression expression, ExpressionTypingContext context, boolean isStatement) { JetExpression innerExpression = expression.getExpression(); if (innerExpression == null) { return null; } - return DataFlowUtils.checkType(facade.getType(innerExpression, context.replaceScope(context.scope)), expression, context); + return DataFlowUtils.checkType(facade.getType(innerExpression, context.replaceScope(context.scope), isStatement), expression, context); } @Override @@ -479,7 +483,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context) { - return context.getServices().getBlockReturnedType(context.scope, expression, CoercionStrategy.NO_COERCION, context); + return visitBlockExpression(expression, context, false); + } + + public JetType visitBlockExpression(JetBlockExpression expression, ExpressionTypingContext context, boolean isStatement) { + return context.getServices().getBlockReturnedType(context.scope, expression, isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION, context); } @Override @@ -611,6 +619,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context) { + return visitUnaryExpression(expression, context, false); + } + + public JetType visitUnaryExpression(JetUnaryExpression expression, ExpressionTypingContext context, boolean isStatement) { JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression == null) return null; JetSimpleNameExpression operationSign = expression.getOperationReference(); @@ -619,9 +631,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { referencedName = referencedName == null ? " " : referencedName; context.labelResolver.enterLabeledElement(referencedName.substring(1), baseExpression); // TODO : Some processing for the label? - JetType type = DataFlowUtils.checkType(facade.getType(baseExpression, context.replaceExpectedReturnType(context.expectedType)), expression, context); + ExpressionTypingContext newContext = context.replaceExpectedReturnType(context.expectedType); + JetType type = facade.getType(baseExpression, newContext, isStatement); context.labelResolver.exitLabeledElement(baseExpression); - return type; + return DataFlowUtils.checkType(type, expression, context); } IElementType operationType = operationSign.getReferencedNameElementType(); String name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType); @@ -835,6 +848,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } private JetType assignmentIsNotAnExpressionError(JetBinaryExpression expression, ExpressionTypingContext context) { + facade.checkStatementType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); context.trace.report(ASSIGNMENT_IN_EXPRESSION_CONTEXT.on(expression)); return null; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 961fb6fc9b3..059baf138fe 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -52,7 +52,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { @Override - public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext contextWithExpectedType) { + public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext context) { + return visitIfExpression(expression, context, false); + } + + public JetType visitIfExpression(JetIfExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); JetExpression condition = expression.getCondition(); checkCondition(context.scope, condition, context); @@ -71,7 +75,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (type != null && JetStandardClasses.isNothing(type)) { facade.setResultingDataFlowInfo(elseInfo); } - return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); + return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType), expression, contextWithExpectedType, isStatement); } return null; } @@ -80,10 +84,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (type != null && JetStandardClasses.isNothing(type)) { facade.setResultingDataFlowInfo(thenInfo); } - return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType); + return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, contextWithExpectedType), expression, contextWithExpectedType, isStatement); } - JetType thenType = context.getServices().getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), CoercionStrategy.NO_COERCION, contextWithExpectedType.replaceDataFlowInfo(thenInfo)); - JetType elseType = context.getServices().getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), CoercionStrategy.NO_COERCION, contextWithExpectedType.replaceDataFlowInfo(elseInfo)); + CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION; + JetType thenType = context.getServices().getBlockReturnedTypeWithWritableScope(thenScope, Collections.singletonList(thenBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(thenInfo)); + JetType elseType = context.getServices().getBlockReturnedTypeWithWritableScope(elseScope, Collections.singletonList(elseBranch), coercionStrategy, contextWithExpectedType.replaceDataFlowInfo(elseInfo)); JetType result; if (thenType == null) { @@ -105,11 +110,18 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { else if (jumpInElse && !jumpInThen) { facade.setResultingDataFlowInfo(thenInfo); } - return result; + if (result == null) return null; + return DataFlowUtils.checkImplicitCast(result, expression, contextWithExpectedType, isStatement); } @Override - public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType) { + public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext context) { + return visitWhileExpression(expression, context, false); + } + + public JetType visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { + if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); JetExpression condition = expression.getCondition(); checkCondition(context.scope, condition, context); @@ -150,7 +162,12 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } @Override - public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType) { + public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext context) { + return visitDoWhileExpression(expression, context, false); + } + public JetType visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { + if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); JetExpression body = expression.getBody(); JetScope conditionScope = context.scope; @@ -179,7 +196,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } @Override - public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType) { + public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext context) { + return visitForExpression(expression, context, false); + } + + public JetType visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { + if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); JetParameter loopParameter = expression.getLoopParameter(); JetExpression loopRange = expression.getLoopRange(); @@ -417,6 +440,4 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { context.labelResolver.recordLabel(expression, context); return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context); } - - } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index e8e4e992221..3ff9bd46936 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.TypeUtils; @@ -18,8 +19,7 @@ import org.jetbrains.jet.lexer.JetTokens; import java.util.List; -import static org.jetbrains.jet.lang.diagnostics.Errors.AUTOCAST_IMPOSSIBLE; -import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH; +import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST; /** @@ -154,4 +154,30 @@ public class DataFlowUtils { context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType)); return expressionType; } + + @Nullable + public static JetType checkStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context) { + if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(context.expectedType)) { + context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType)); + return null; + } + return JetStandardClasses.getUnitType(); + } + + @Nullable + public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement) { + if (expressionType != null && context.expectedType == TypeUtils.NO_EXPECTED_TYPE && !isStatement && + (JetStandardClasses.isUnit(expressionType) || JetStandardClasses.isAny(expressionType))) { + context.trace.report(IMPLICIT_CAST_TO_UNIT_OR_ANY.on(expression, expressionType)); + + } + return expressionType; + } + + @Nullable + public static JetType illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) { + facade.checkStatementType(expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)); + context.trace.report(EXPRESSION_EXPECTED.on(expression, expression)); + return null; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingFacade.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingFacade.java index cb51c922781..033d70d3578 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingFacade.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingFacade.java @@ -14,7 +14,7 @@ public interface ExpressionTypingFacade { @Nullable JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context); - + @Nullable - JetType getTypeForStatement(@NotNull JetExpression expression, ExpressionTypingContext context); + JetType getType(@NotNull JetExpression expression, ExpressionTypingContext context, boolean isStatement); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingInternals.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingInternals.java index 200174c6bc5..dc80d0c61f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingInternals.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingInternals.java @@ -24,4 +24,6 @@ import org.jetbrains.jet.lang.types.JetType; JetType getSelectorReturnType(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetExpression selectorExpression, @NotNull ExpressionTypingContext context); void checkInExpression(JetElement callElement, @NotNull JetSimpleNameExpression operationSign, @NotNull JetExpression left, @NotNull JetExpression right, ExpressionTypingContext context); + + void checkStatementType(@NotNull JetExpression expression, ExpressionTypingContext context); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index 66769cd0f6e..39f1ba5c916 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -48,7 +48,11 @@ public class ExpressionTypingServices { @NotNull public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType) { - JetType type = getType(scope, expression, expectedType); + return safeGetType(scope, expression, expectedType, DataFlowInfo.EMPTY); + } + + public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo) { + JetType type = getType(scope, expression, expectedType, dataFlowInfo); if (type != null) { return type; } @@ -61,7 +65,7 @@ public class ExpressionTypingServices { } @Nullable - public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, DataFlowInfo dataFlowInfo) { + public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull DataFlowInfo dataFlowInfo) { ExpressionTypingContext context = ExpressionTypingContext.newContext( semanticServices, new HashMap(), new HashMap>(), new LabelResolver(), @@ -133,7 +137,7 @@ public class ExpressionTypingServices { getBlockReturnedType(newContext.scope, blockExpression, CoercionStrategy.COERCION_TO_UNIT, context); } else { - expressionTypingFacade.getType(bodyExpression, newContext); + expressionTypingFacade.getType(bodyExpression, newContext, !blockBody); } } @@ -159,7 +163,7 @@ public class ExpressionTypingServices { assert bodyExpression != null; JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace); expressionTypingFacade.getType(bodyExpression, ExpressionTypingContext.newContext(semanticServices, new HashMap(), new HashMap>(), new LabelResolver(), - trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN, false)); + trace, functionInnerScope, DataFlowInfo.EMPTY, NO_EXPECTED_TYPE, FORBIDDEN, false), !function.hasBlockBody()); //todo function literals final Collection returnedExpressions = Lists.newArrayList(); if (function.hasBlockBody()) { @@ -225,13 +229,13 @@ public class ExpressionTypingServices { final boolean[] mismatch = new boolean[1]; ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch); newContext = createContext(newContext, errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); - result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext); + result = blockLevelVisitor.getType(statementExpression, newContext, true); if (mismatch[0]) { TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace); mismatch[0] = false; ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch); newContext = createContext(newContext, interceptingTrace, scope, newContext.dataFlowInfo, NO_EXPECTED_TYPE, context.expectedReturnType); - result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext); + result = blockLevelVisitor.getType(statementExpression, newContext, true); if (mismatch[0]) { temporaryTraceExpectingUnit.commit(); } @@ -245,11 +249,11 @@ public class ExpressionTypingServices { } else { newContext = createContext(newContext, trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType); - result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext); + result = blockLevelVisitor.getType(statementExpression, newContext, true); } } else { - result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext); + result = blockLevelVisitor.getType(statementExpression, newContext, true); if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) { boolean mightBeUnit = false; if (statementExpression instanceof JetDeclaration) { @@ -271,7 +275,7 @@ public class ExpressionTypingServices { } } else { - result = blockLevelVisitor.getTypeForStatement(statementExpression, newContext); + result = blockLevelVisitor.getType(statementExpression, newContext, true); } DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorDispatcher.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorDispatcher.java index 36db4c054db..1edb38e0318 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorDispatcher.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorDispatcher.java @@ -40,7 +40,7 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor 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/testData/diagnostics/tests/control-flow-analysis/kt510.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt510.jet similarity index 100% rename from compiler/testData/diagnostics/tests/control-flow-analysis/kt510.jet rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/kt510.jet diff --git a/compiler/testData/diagnostics/tests/control-flow-analysis/kt607.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt607.jet similarity index 100% rename from compiler/testData/diagnostics/tests/control-flow-analysis/kt607.jet rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/kt607.jet diff --git a/compiler/testData/diagnostics/tests/control-flow-analysis/kt609.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt609.jet similarity index 100% rename from compiler/testData/diagnostics/tests/control-flow-analysis/kt609.jet rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/kt609.jet diff --git a/compiler/testData/diagnostics/tests/control-flow-analysis/kt610.jet b/compiler/testData/diagnostics/tests/controlFlowAnalysis/kt610.jet similarity index 100% rename from compiler/testData/diagnostics/tests/control-flow-analysis/kt610.jet rename to compiler/testData/diagnostics/tests/controlFlowAnalysis/kt610.jet diff --git a/compiler/testData/diagnostics/tests/control/ForWithoutBraces.jet b/compiler/testData/diagnostics/tests/controlStructures/ForWithoutBraces.jet similarity index 100% rename from compiler/testData/diagnostics/tests/control/ForWithoutBraces.jet rename to compiler/testData/diagnostics/tests/controlStructures/ForWithoutBraces.jet diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet new file mode 100644 index 00000000000..f9d9a50e4f4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet @@ -0,0 +1,126 @@ +namespace kt770_351_735 + +//+JDK + +//KT-770 Reference is not resolved to anything, but is not marked unresolved +fun main(args : Array) { + var i = 0 + when (i) { + 1 => i-- + 2 => i = 2 // i is surrounded by a black border + else => j = 2 + } + System.out?.println(i) +} + +//KT-351 Distinguish statement and expression positions +val w = while (true) {} + +fun foo() { + var z = 2 + val r = { // type fun(): Int is inferred + if (true) { + 2 + } + else { + z = 34 + } + } + val f: fun(): Int = r + val g: fun(): Any = r +} + +//KT-735 Statements without braces are prohibited on the right side of when entries. +fun box() : Int { + val d = 2 + var z = 0 + when(d) { + is 5, is 3 => z++ + else => z = -1000 + } + return z +} + +//More tests + +fun test1() = while(true) {} +fun test2(): Unit = while(true) {} + +fun testCoercionToUnit() { + val simple: fun(): Unit = { + 41 + } + val withIf: fun(): Unit = { + if (true) { + 3 + } else { + 45 + } + } + val i = 34 + val withWhen : fun() : Unit = { + when(i) { + is 1 => { + val d = 34 + "1" + doSmth(d) + + } + is 2 => '4' + else => true + } + } + + var x = 43 + val checkType = { + if (true) { + x = 4 + } else { + 45 + } + } + val f : fun() : String = checkType +} + +fun doSmth(i: Int) {} + +fun testImplicitCoercion() { + val d = 21 + var z = 0 + var i = when(d) { + is 3 => null + is 4 => { val z = 23 } + else => z = 20 + } + + var u = when(d) { + is 3 => { + z = 34 + } + else => z-- + } + + var iff = if (true) { + z = 34 + } + val g = if (true) 4 + val h = if (false) 4 else {} + + bar(if (true) { + 4 + } + else { + z = 342 + }) +} + +fun bar(a: Unit) {} + +fun testStatementInExpressionContext() { + var z = 34 + val a1: Unit = z = 334 + val a2: Unit = while(true) {} + val f = for (i in 1..10) {} + if (true) return z = 34 + return while (true) {} +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt786.jet b/compiler/testData/diagnostics/tests/controlStructures/kt786.jet new file mode 100644 index 00000000000..665af148d31 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlStructures/kt786.jet @@ -0,0 +1,26 @@ +namespace kt786 + +//KT-786 Exception on incomplete code with 'when' +fun foo() : Int { + val d = 2 + var z = 0 + when(d) { + is 5, is 3 => z++ + else => { z = -1000 } + return z => 34 + } +} + +//test unreachable code +fun fff(): Int { + var d = 3 + when(d) { + is 4 => 21 + return 2 => return 47 + bar() => 45 + 444 => true + } + return 34 +} + +fun bar(): Int = 8 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.jet b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.jet new file mode 100644 index 00000000000..3fdb3fc0a75 --- /dev/null +++ b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.jet @@ -0,0 +1,34 @@ +namespace kt244 + +//+JDK + +// KT-244 Use dataflow info while resolving variable initializers + +fun f(s: String?) { + if (s != null) { + s.length //ok + var i = s.length //error: Only safe calls are allowed on a nullable receiver + System.out?.println(s.length) //error + } +} + +// more tests +class A(a: String?) { + val b = if (a != null) a.length else 1 + { + if (a != null) { + val c = a.length + } + } + + val i : Int + + { + if (a is String) { + i = a.length + } + else { + i = 3 + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/kt629.jet b/compiler/testData/diagnostics/tests/regressions/kt629.jet index 3d52542ad7f..f0c8780ad9a 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt629.jet +++ b/compiler/testData/diagnostics/tests/regressions/kt629.jet @@ -18,6 +18,6 @@ fun box() : Boolean { fun box2() : Boolean { - var c = A() + var c = A() return (c.p = "yeah") && true } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 0a84cae970b..b7ceb359a44 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -30,6 +30,8 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeConstructor; import org.jetbrains.jet.plugin.JetLanguage; import org.junit.Assert; @@ -156,9 +158,23 @@ public class ReadClassDataTest extends UsefulTestCase { for (int i = 0; i < a.getValueParameters().size(); ++i) { compareAnything(ValueParameterDescriptor.class, a.getValueParameters().get(i), b.getValueParameters().get(i)); } - Assert.assertEquals(a.getReturnType(), b.getReturnType()); + compareTypes(a.getReturnType(), b.getReturnType()); System.out.println("fun " + a.getName() + "(...): " + a.getReturnType()); } + + private void compareAnything(Object a, Object b) { + if (a instanceof JetType || b instanceof JetType) { + compareTypes((JetType) a, (JetType) b); + } else { + Assert.assertEquals(a, b); + } + } + + private void compareTypes(JetType a, JetType b) { + // cannot just call a.equals(b) because "a" and "b" were created in different environments, + // TypeConstructor does not override equals() + Assert.assertEquals(a.toString(), b.toString()); + } private void compareAnything(Class clazz, T a, T b) { System.out.println("Comparing " + clazz); @@ -182,7 +198,7 @@ public class ReadClassDataTest extends UsefulTestCase { System.out.println(method.getName()); Object ap = invoke(method, a); Object bp = invoke(method, b); - Assert.assertEquals(ap, bp); + compareAnything(ap, bp); } } diff --git a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index e765cef474a..d9071141007 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -326,9 +326,9 @@ public class JetTypeCheckerTest extends JetLiteFixture { } public void testLoops() throws Exception { - assertType("while (1) {1}", "Unit"); - assertType("do {1} while(1)", "Unit"); - assertType("for (i in 1) {1}", "Unit"); + assertType("{ while (1) {1} }", "fun(): Unit"); + assertType("{ do {1} while(1) }", "fun(): Unit"); + assertType("{ for (i in 1) {1} }", "fun(): Unit"); } public void testFunctionLiterals() throws Exception { diff --git a/examples/src/benchmarks/FList.kt b/examples/src/benchmarks/FList.kt index 5d806215920..17179b006bb 100644 --- a/examples/src/benchmarks/FList.kt +++ b/examples/src/benchmarks/FList.kt @@ -30,7 +30,7 @@ class StandardFList (override val head: T, override val tail: FList) : FLi fun FList.plus2(element: T): FList = when(this) { - is EmptyFList => OneElementFList(element) + is EmptyFList<*> => OneElementFList(element) else => StandardFList(element, this) } @@ -67,4 +67,4 @@ fun main(args: Array) { 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/handlers/JetFunctionInsertHandler.java b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java index 68aafbc70a1..8a35b107592 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/JetFunctionInsertHandler.java @@ -22,6 +22,10 @@ public class JetFunctionInsertHandler implements InsertHandler { @Override public void handleInsert(InsertionContext context, LookupElement item) { + if (context.getCompletionChar() == '(') { + context.setAddCompletionChar(false); + } + int startOffset = context.getStartOffset(); int lookupStringLength = item.getLookupString().length(); int endOffset = startOffset + lookupStringLength; diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 7224322b46e..bb955817b2c 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -17,12 +17,16 @@ 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.*; +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.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScopeUtils; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.NamespaceType; import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler; @@ -105,6 +109,7 @@ class JetSimpleNameReference extends JetPsiReference { @NotNull Iterable descriptors, @NotNull final JetScope scope ) { final Set descriptorsSet = Sets.newHashSet(descriptors); + descriptorsSet.removeAll( Collections2.filter(JetScopeUtils.getAllExtensions(scope), new Predicate() { @Override @@ -121,6 +126,11 @@ class JetSimpleNameReference extends JetPsiReference { @NotNull final JetScope externalScope, @NotNull final ReceiverDescriptor receiverDescriptor ) { + // It's impossible to add extension function for namespace + if (receiverDescriptor.getType() instanceof NamespaceType) { + return descriptors; + } + Set descriptorsSet = Sets.newHashSet(descriptors); descriptorsSet.addAll(Collections2.filter(JetScopeUtils.getAllExtensions(externalScope), @@ -138,7 +148,7 @@ class JetSimpleNameReference extends JetPsiReference { List result = Lists.newArrayList(); for (final DeclarationDescriptor descriptor : descriptors) { - LookupElementBuilder element = LookupElementBuilder.create(descriptor.getName()); + LookupElementBuilder element = LookupElementBuilder.create(descriptor, descriptor.getName()); String typeText = ""; String tailText = ""; boolean tailTextGrayed = false; @@ -155,6 +165,7 @@ 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 @@ -175,6 +186,7 @@ class JetSimpleNameReference extends JetPsiReference { else { typeText = DescriptorRenderer.TEXT.render(descriptor); } + element = element.setTailText(tailText, tailTextGrayed).setTypeText(typeText); PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getOriginal()); 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/basic/OverloadFunctions.kt b/idea/testData/completion/basic/OverloadFunctions.kt new file mode 100644 index 00000000000..757a0c0f8ce --- /dev/null +++ b/idea/testData/completion/basic/OverloadFunctions.kt @@ -0,0 +1,24 @@ +namespace Test.MyTest + +class A { + class object { + public fun testOther() { + + } + + public fun testOther(a: Boolean) { + + } + + public fun testOther(a: Int) { + + } + } +} + +fun testMy() { + A.test +} + +// EXIST: testOther +// NUMBER: 3 \ No newline at end of file diff --git a/idea/testData/completion/basic/SubpackageInFun.kt b/idea/testData/completion/basic/SubpackageInFun.kt new file mode 100644 index 00000000000..52a9b1022e7 --- /dev/null +++ b/idea/testData/completion/basic/SubpackageInFun.kt @@ -0,0 +1,7 @@ +namespace Test.MyTest + +fun test() { + Test. +} + +// EXIST: MyTest \ No newline at end of file diff --git a/idea/testData/completion/handlers/SingleBrackets.kt b/idea/testData/completion/handlers/SingleBrackets.kt new file mode 100644 index 00000000000..1593bc01db3 --- /dev/null +++ b/idea/testData/completion/handlers/SingleBrackets.kt @@ -0,0 +1,17 @@ +namespace Test.MyTest + +class A { + class object { + public fun testOther(a: Boolean) { + + } + + public fun testOther(a: Int) { + + } + } +} + +fun testMy() { + A.testOther +} \ No newline at end of file diff --git a/idea/testData/completion/handlers/SingleBrackets.kt.after b/idea/testData/completion/handlers/SingleBrackets.kt.after new file mode 100644 index 00000000000..94e927574b8 --- /dev/null +++ b/idea/testData/completion/handlers/SingleBrackets.kt.after @@ -0,0 +1,17 @@ +namespace Test.MyTest + +class A { + class object { + public fun testOther(a: Boolean) { + + } + + public fun testOther(a: Int) { + + } + } +} + +fun testMy() { + A.testOther() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java index 624eb685c3e..7e5a32a28f5 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java +++ b/idea/tests/org/jetbrains/jet/completion/JetCompletionTestBase.java @@ -8,6 +8,7 @@ import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.openapi.projectRoots.Sdk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.io.BufferedReader; @@ -59,6 +60,11 @@ public abstract class JetCompletionTestBase extends LightCompletionTestCase { assertContainsItems(itemsShouldExist(getFile().getText())); assertNotContainItems(itemsShouldAbsent(getFile().getText())); + + Integer itemsNumber = getExpectedNumber(getFile().getText()); + if (itemsNumber != null) { + assertEquals(itemsNumber.intValue(), myItems.length); + } } @Override @@ -85,6 +91,16 @@ public abstract class JetCompletionTestBase extends LightCompletionTestCase { return findListWithPrefix("// ABSENT:", fileText); } + @Nullable + private static Integer getExpectedNumber(String fileText) { + final String[] numberStrings = findListWithPrefix("// NUMBER:", fileText); + if (numberStrings.length > 0) { + return Integer.parseInt(numberStrings[0]); + } + + return null; + } + @NotNull private static String[] findListWithPrefix(String prefix, String fileText) { ArrayList result = new ArrayList(); diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java index f265bde4714..ad0ed374b78 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/FunctionsHandlerTest.java @@ -20,6 +20,14 @@ public class FunctionsHandlerTest extends LightCompletionTestCase { checkResultByFile("ParamsFunction.kt.after"); } + public void testSingleBrackets() { + configureByFile("SingleBrackets.kt"); + type('('); + checkResultByFile("SingleBrackets.kt.after"); + } + + // public void + @Override protected String getTestDataPath() { return new File(PluginTestCaseBase.getTestDataPathBase(), "/completion/handlers/").getPath() + 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/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java index a999ce2f298..b057014caf2 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) @@ -24,4 +26,9 @@ public @interface JetMethod { * @return is this type returnTypeNullable */ boolean nullableReturnType() default false; + + /** + * Return type type unless java type is correct Kotlin type. + */ + String returnType () default ""; } diff --git a/stdlib/src/jet/typeinfo/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 76% rename from stdlib/src/jet/typeinfo/JetParameter.java rename to stdlib/src/jet/typeinfo/JetValueParameter.java index bae06e264b1..db0a4f52605 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 */ @@ -32,4 +34,9 @@ public @interface JetParameter { * @return if this parameter has default value */ boolean hasDefaultValue () default false; + + /** + * @return type unless Java type is correct Kotlin type. + */ + String type() default ""; } diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index a5ad5850ebe..dfdda4e367e 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -376,7 +376,7 @@ public abstract class TypeInfo implements JetObject { return false; } if (superType.projections == null || superType.projections.length != projections.length) { - throw new IllegalArgumentException("inconsistent type infos for the same class"); + throw new IllegalArgumentException("inconsistent type info for the same class"); } for (int i = 0; i < projections.length; i++) { // TODO handle variance here @@ -451,18 +451,18 @@ public abstract class TypeInfo implements JetObject { if(klass == null) return null; - lock.readLock().lock(); +// lock.readLock().lock(); Signature sig = map.get(klass); - lock.readLock().unlock(); +// lock.readLock().unlock(); if (sig == null) { - lock.writeLock().lock(); +// lock.writeLock().lock(); sig = map.get(klass); if (sig == null) { sig = internalParse(klass); } - lock.writeLock().unlock(); +// lock.writeLock().unlock(); } return sig; } @@ -536,13 +536,20 @@ public abstract class TypeInfo implements JetObject { } public void parseVars(Signature signature) { - while(cur < string.length && string[cur] == 'T') { - if(signature.variables == null) { - signature.variables = new LinkedList(); - signature.varNames = new HashMap(); + if (cur < string.length && string[cur] == '<') { + cur++; + while(cur < string.length && string[cur] != '>') { + if(signature.variables == null) { + signature.variables = new LinkedList(); + signature.varNames = new HashMap(); + } + if (string[cur] != 'T') { + throw new IllegalStateException(new String(string)); + } + cur++; + signature.variables.add(parseVar(signature)); } cur++; - signature.variables.add(parseVar(signature)); } signature.variables = signature.variables == null ? Collections.emptyList() : signature.variables; signature.varNames = signature.varNames == null ? Collections.emptyMap() : signature.varNames;