From 9d0a2c7243b8a8497780467610678543d608dcd3 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 13 Dec 2011 13:26:42 +0200 Subject: [PATCH 01/22] (slightly modified) contribution of Sergey Ignatov of methods for strings and arrays --- stdlib/ktSrc/Arrays.kt | 21 ++++++++++++++ stdlib/ktSrc/JavaUtil.kt | 14 ++++------ stdlib/ktSrc/String.kt | 59 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 stdlib/ktSrc/Arrays.kt create mode 100644 stdlib/ktSrc/String.kt diff --git a/stdlib/ktSrc/Arrays.kt b/stdlib/ktSrc/Arrays.kt new file mode 100644 index 00000000000..c8ddc2b5c70 --- /dev/null +++ b/stdlib/ktSrc/Arrays.kt @@ -0,0 +1,21 @@ +namespace std + +// 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 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..22e3c9864d9 --- /dev/null +++ b/stdlib/ktSrc/String.kt @@ -0,0 +1,59 @@ +namespace std + +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.bytes : ByteArray + get() = getBytes() + +// "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 From c4fd2e564fcd487af3a6bbaa86abed737b9e41d5 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Tue, 13 Dec 2011 16:15:43 +0400 Subject: [PATCH 02/22] 1. namespace class should not be accessible from Kotlin despite the fact we don't have kotlin class descriptor for it. 2. testdata is corrected due to the fact frontend has wrong qualified name in trace for root namespace --- .../org/jetbrains/jet/lang/resolve/java/JavaPackageScope.java | 3 +++ idea/testData/completion/basic/ExtendClassName.kt | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) 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/idea/testData/completion/basic/ExtendClassName.kt b/idea/testData/completion/basic/ExtendClassName.kt index 47daf28eff9..e25d7e3528f 100644 --- a/idea/testData/completion/basic/ExtendClassName.kt +++ b/idea/testData/completion/basic/ExtendClassName.kt @@ -1,3 +1,5 @@ +namespace foo + open class MySecondClass() { } @@ -10,4 +12,4 @@ class A() : My { } } -// EXIST: MySecondClass, MyFirstClass \ No newline at end of file +// EXIST: MySecondClass, MyFirstClass From 739f3b2a36919c29cfcd40d9e1c8917e391b542d Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 13 Dec 2011 17:38:57 +0400 Subject: [PATCH 03/22] Root namespace naming problems fixed. Failing test reverted to the initial state --- .../src/org/jetbrains/jet/lang/psi/JetPsiUtil.java | 8 ++++++-- idea/testData/completion/basic/ExtendClassName.kt | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) 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/idea/testData/completion/basic/ExtendClassName.kt b/idea/testData/completion/basic/ExtendClassName.kt index e25d7e3528f..c4ae4f6575d 100644 --- a/idea/testData/completion/basic/ExtendClassName.kt +++ b/idea/testData/completion/basic/ExtendClassName.kt @@ -1,5 +1,3 @@ -namespace foo - open class MySecondClass() { } From ff055399a7e7009334e6d22de38bc4ad58e224e5 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 13 Dec 2011 15:45:18 +0200 Subject: [PATCH 04/22] house keeping --- .../jet/codegen/NamespaceCodegen.java | 4 +- .../testData/codegen/inputStreamIterator.jet | 1 + stdlib/ktSrc/Arrays.kt | 8 ++ .../ktSrc/{StandardLibrary.kt => JavaIo.kt} | 75 +++++++++---------- stdlib/ktSrc/String.kt | 7 +- 5 files changed, 51 insertions(+), 44 deletions(-) rename stdlib/ktSrc/{StandardLibrary.kt => JavaIo.kt} (86%) 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/testData/codegen/inputStreamIterator.jet b/compiler/testData/codegen/inputStreamIterator.jet index 7be02b077f2..85ff66b2ba7 100644 --- a/compiler/testData/codegen/inputStreamIterator.jet +++ b/compiler/testData/codegen/inputStreamIterator.jet @@ -1,3 +1,4 @@ +import std.* import std.io.* import java.io.* diff --git a/stdlib/ktSrc/Arrays.kt b/stdlib/ktSrc/Arrays.kt index c8ddc2b5c70..197cd1c236c 100644 --- a/stdlib/ktSrc/Arrays.kt +++ b/stdlib/ktSrc/Arrays.kt @@ -1,5 +1,7 @@ namespace std +import java.io.ByteArrayInputStream + // Array "constructor" inline fun array(vararg t : T) : Array = t @@ -19,3 +21,9 @@ 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 86% rename from stdlib/ktSrc/StandardLibrary.kt rename to stdlib/ktSrc/JavaIo.kt index 999cecbad2c..020809cc19b 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 @@ -107,4 +66,38 @@ namespace io { })) fun readLine() : String? = stdin.readLine() + + 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) } \ No newline at end of file diff --git a/stdlib/ktSrc/String.kt b/stdlib/ktSrc/String.kt index 22e3c9864d9..4df7c099d29 100644 --- a/stdlib/ktSrc/String.kt +++ b/stdlib/ktSrc/String.kt @@ -1,5 +1,7 @@ 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) @@ -35,8 +37,8 @@ inline fun String.substring(i0 : Int, i1 : Int) = (this as java.lang.String).su inline val String.size : Int get() = length() -inline val String.bytes : ByteArray - get() = getBytes() +inline val String.reader : StringReader + get() = StringReader(this) // "constructors" for String @@ -57,3 +59,4 @@ 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 + From ac29a020e26df863568bfaaef7377e830d3fe7ab Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 17:52:38 +0400 Subject: [PATCH 05/22] do not allow mapping of error type to JVM type --- .../backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 7fa09823a80..d98c928f379 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -248,6 +248,11 @@ public class JetTypeMapper { } 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"); From 3419df7d0c67cd1642b6ec6f675d78a321a0a9e0 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 13 Dec 2011 16:00:22 +0200 Subject: [PATCH 06/22] a bit more methods (previously broke compilation) --- stdlib/ktSrc/JavaIo.kt | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/stdlib/ktSrc/JavaIo.kt b/stdlib/ktSrc/JavaIo.kt index 020809cc19b..71ab785f556 100644 --- a/stdlib/ktSrc/JavaIo.kt +++ b/stdlib/ktSrc/JavaIo.kt @@ -65,7 +65,7 @@ namespace io { } })) - fun readLine() : String? = stdin.readLine() + inline fun readLine() : String? = stdin.readLine() fun InputStream.iterator() : ByteIterator = object: ByteIterator() { @@ -75,29 +75,25 @@ namespace io { 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) - // inline fun InputStream.buffered(bufferSize: Int) = BufferedInputStream(this, bufferSize) - - val InputStream.reader : InputStreamReader + inline val InputStream.reader : InputStreamReader get() = InputStreamReader(this) - val InputStream.bufferedReader : BufferedReader + 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, charsetNme) - - inline fun InputStream.reader(charset: Charset) = InputStreamReader(this, charset) + inline fun InputStream.reader(charsetName: String) = InputStreamReader(this, charsetName) inline fun InputStream.reader(charsetDecoder: CharsetDecoder) = InputStreamReader(this, charsetDecoder) - */ - // val Reader.buffered : BufferedReader - // get() = if(this instanceof BufferedReader) this else BufferedReader(this) + inline val InputStream.buffered : BufferedInputStream + get() = if(this is BufferedInputStream) this else BufferedInputStream(this) - // inline fun Reader.buffered(bufferSize: Int) = BufferedReader(this, bufferSize) +// 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 From b1cf0ffcee7e48738a0ae8c6e51de81db415c1ba Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:28:47 +0400 Subject: [PATCH 07/22] more class and method signatures, use writer wrapper (not yet complete) own writer will be used to write both java and kotlin signatures --- .../jet/codegen/BothSignatureWriter.java | 211 ++++++++++++++++++ .../codegen/ImplementationBodyCodegen.java | 110 +++++---- .../jetbrains/jet/codegen/JetTypeMapper.java | 154 ++++++++----- .../jet/codegen/JvmClassSignature.java | 36 +++ .../jet/lang/resolve/StdlibNames.java | 1 + .../class/ExtendsAbstractListT.java | 6 + .../class/ExtendsAbstractListT.kt | 1 + .../class/ImplementsListString.java | 7 + .../class/ImplementsListString.kt | 1 + .../class/ImplementsMapPP.java | 7 + .../class/ImplementsMapPP.kt | 1 + .../method/QExtendsListString.java | 8 + .../method/QExtendsListString.kt | 3 + .../method/QExtendsString.java | 8 + .../method/QExtendsString.kt | 1 + 15 files changed, 453 insertions(+), 102 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt create mode 100644 compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt create mode 100644 compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java create mode 100644 compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt 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..e63487fc198 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -0,0 +1,211 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureVisitor; +import org.objectweb.asm.signature.SignatureWriter; +import org.objectweb.asm.util.CheckSignatureAdapter; + +import java.util.Stack; + +/** + * @author Stepan Koltsov + */ +public class BothSignatureWriter { + + private static final boolean DEBUG_SIGNATURE_WRITER = true; + + enum Mode { + METHOD(CheckSignatureAdapter.METHOD_SIGNATURE), + CLASS(CheckSignatureAdapter.CLASS_SIGNATURE), + ; + + private final int asmType; + + Mode(int asmType) { + this.asmType = asmType; + } + } + + private final SignatureWriter signatureWriter = new SignatureWriter(); + private final SignatureVisitor signatureVisitor; + private final Mode mode; + + public BothSignatureWriter(Mode mode) { + this.mode = mode; + if (DEBUG_SIGNATURE_WRITER) { + signatureVisitor = new CheckSignatureAdapter(mode.asmType, signatureWriter); + } else { + signatureVisitor = signatureWriter; + } + } + + // TODO: ignore when debugging is disabled + private Stack visitors = new Stack(); + + private void push(SignatureVisitor visitor) { + visitors.push(visitor); + } + + private void pop() { + visitors.pop(); + } + + + + private SignatureVisitor signatureVisitor() { + return !visitors.isEmpty() ? visitors.peek() : signatureVisitor; + } + + private void checkTopLevel() { + if (DEBUG_SIGNATURE_WRITER) { + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + } + + private void checkMode(Mode mode) { + if (DEBUG_SIGNATURE_WRITER) { + if (mode != this.mode) { + throw new IllegalStateException(); + } + } + } + + + /** + * Shortcut + */ + public void writeAsmType(Type asmType) { + switch (asmType.getSort()) { + case Type.OBJECT: + writeClassBegin(asmType.getInternalName()); + writeClassEnd(); + return; + case Type.ARRAY: + writeArrayType(); + writeAsmType(asmType.getElementType()); + writeArrayEnd(); + return; + default: + String descriptor = asmType.getDescriptor(); + if (descriptor.length() != 1) { + throw new IllegalStateException(); + } + signatureVisitor().visitBaseType(descriptor.charAt(0)); + } + } + + public void writeClassBegin(String internalName) { + signatureVisitor().visitClassType(internalName); + } + + public void writeClassEnd() { + signatureVisitor().visitEnd(); + } + + public void writeArrayType() { + push(signatureVisitor().visitArrayType()); + } + + public void writeArrayEnd() { + pop(); + } + + public void writeTypeArgument(char c) { + push(signatureVisitor().visitTypeArgument(c)); + } + + public void writeTypeArgumentEnd() { + pop(); + } + + public void writeTypeVariable(final String name) { + signatureVisitor().visitTypeVariable(name); + } + + public void writeFormalTypeParameter(final String name) { + checkTopLevel(); + + signatureVisitor().visitFormalTypeParameter(name); + } + + public void writeClassBound() { + push(signatureVisitor().visitClassBound()); + } + + public void writeClassBoundEnd() { + pop(); + } + + public void writeInterfaceBound() { + push(signatureVisitor().visitInterfaceBound()); + } + + public void writeInterfaceBoundEnd() { + pop(); + } + + public void writeParameterType() { + push(signatureVisitor().visitParameterType()); + } + + public void writeParameterTypeEnd() { + pop(); + } + + public void writeReturnType() { + push(signatureVisitor().visitReturnType()); + } + + public void writeReturnTypeEnd() { + pop(); + } + + public void writeSuperclass() { + checkTopLevel(); + checkMode(Mode.CLASS); + + push(signatureVisitor().visitSuperclass()); + } + + public void writeSuperclassEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + public void writeInterface() { + checkTopLevel(); + checkMode(Mode.CLASS); + + push(signatureVisitor().visitInterface()); + } + + public void writeInterfaceEnd() { + pop(); + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + } + + + + + @Nullable + public String makeJavaString() { + if (!visitors.isEmpty()) { + throw new IllegalStateException(); + } + return signatureWriter.toString(); + } + + @Nullable + public String makeKotlinString() { + // TODO: not implemented yet + return null; + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 0af0a1ef2e8..7d8298b489a 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.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.getGenericSignature(), + signature.getSuperclassName(), + signature.getInterfaces().toArray(new String[0]) ); v.visitSource(myClass.getContainingFile().getName(), null); @@ -94,30 +77,57 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { annotationVisitor.visitEnd(); } } + + private JvmClassSignature signature() { + String genericSignature; + List superInterfaces; - @Nullable - private String genericSignature() { - List typeParameters = descriptor.getTypeConstructor().getParameters(); - - SignatureWriter signatureWriter = new SignatureWriter(); - SignatureVisitor signatureVisitor = JetTypeMapper.DEBUG_SIGNATURE_WRITER - ? new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, signatureWriter) - : signatureWriter; - for (TypeParameterDescriptor typeParameter : typeParameters) { - signatureVisitor.visitFormalTypeParameter(typeParameter.getName()); - SignatureVisitor classBoundVisitor = signatureVisitor.visitClassBound(); - // TODO: wrong - JetTypeMapper.visitAsmType(classBoundVisitor, JetTypeMapper.TYPE_OBJECT); + { + LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); + + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + + + { // type parameters + List typeParameters = descriptor.getTypeConstructor().getParameters(); + typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); + } + + + { // superclass + signatureVisitor.writeSuperclass(); + if (superClassType == null) { + signatureVisitor.writeClassBegin(superClass); + signatureVisitor.writeClassEnd(); + } else { + typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + } + signatureVisitor.writeSuperclassEnd(); + } + + + { // superinterfaces + superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.isInterface(superClassDescriptor)) { + signatureVisitor.writeInterface(); + Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + signatureVisitor.writeInterfaceEnd(); + superInterfacesLinkedHashSet.add(jvmName.getInternalName()); + } + } + + superInterfaces = new ArrayList(superInterfacesLinkedHashSet); + } + + // TODO: null if class is not generic and does not have generic superclasses + genericSignature = signatureVisitor.makeJavaString(); } - SignatureVisitor superclassSignatureVisitor = signatureVisitor.visitSuperclass(); - // TODO: wrong - superclassSignatureVisitor.visitClassType("java/lang/Object"); - // TODO: add interfaces - superclassSignatureVisitor.visitEnd(); - - // TODO: return null if class is not generic and does not have generic superclasses - - return signatureWriter.toString(); + return new JvmClassSignature(jvmName(), superClass, superInterfaces, genericSignature); } private String jvmName() { @@ -125,6 +135,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } protected void getSuperClass() { + superClass = "java/lang/Object"; + superClassType = null; + List delegationSpecifiers = myClass.getDelegationSpecifiers(); if(myClass instanceof JetClass && ((JetClass) myClass).isTrait()) @@ -136,6 +149,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { assert superType != null; ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); if(!CodegenUtil.isInterface(superClassDescriptor)) { + superClassType = superType; superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), kind).getInternalName(); superCall = specifier; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index d98c928f379..750d036d961 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.*; @@ -165,10 +162,10 @@ public class JetTypeMapper { return mapReturnType(jetType, null); } - @NotNull private Type mapReturnType(final JetType jetType, @Nullable SignatureVisitor signatureVisitor) { + @NotNull private Type mapReturnType(final JetType jetType, @Nullable BothSignatureWriter signatureVisitor) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { if (signatureVisitor != null) { - signatureVisitor.visitBaseType('V'); + signatureVisitor.writeAsmType(Type.VOID_TYPE); } return Type.VOID_TYPE; } @@ -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,11 +234,11 @@ 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); @@ -260,8 +257,9 @@ public class JetTypeMapper { JetType memberType = jetType.getArguments().get(0).getType(); if (signatureVisitor != null) { - SignatureVisitor arraySignatureVisitor = signatureVisitor.visitArrayType(); - mapType(memberType, kind, arraySignatureVisitor, true); + signatureVisitor.writeArrayType(); + mapType(memberType, kind, signatureVisitor, true); + signatureVisitor.writeArrayEnd(); } if (!isGenericsArray(jetType)) { @@ -284,13 +282,14 @@ public class JetTypeMapper { Type asmType = Type.getObjectType(name + (kind == OwnerKind.TRAIT_IMPL ? "$$TImpl" : "")); if (signatureVisitor != null) { - signatureVisitor.visitClassType(asmType.getInternalName()); + signatureVisitor.writeClassBegin(asmType.getInternalName()); for (TypeProjection proj : jetType.getArguments()) { // TODO: +- - SignatureVisitor argumentSignatureVisitor = signatureVisitor.visitTypeArgument('='); - mapType(proj.getType(), kind, argumentSignatureVisitor, true); + signatureVisitor.writeTypeArgument('='); + mapType(proj.getType(), kind, signatureVisitor, true); + signatureVisitor.writeTypeArgumentEnd(); } - signatureVisitor.visitEnd(); + signatureVisitor.writeClassEnd(); } return asmType; @@ -299,7 +298,7 @@ public class JetTypeMapper { if (descriptor instanceof TypeParameterDescriptor) { if (signatureVisitor != null) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) jetType.getConstructor().getDeclarationDescriptor(); - signatureVisitor.visitTypeVariable(typeParameterDescriptor.getName()); + signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName()); } return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); @@ -308,7 +307,7 @@ public class JetTypeMapper { throw new UnsupportedOperationException("Unknown type " + jetType); } - private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable SignatureVisitor signatureVisitor, boolean genericTypeParameter) { + private Type mapKnownAsmType(JetType jetType, Type asmType, @Nullable BothSignatureWriter signatureVisitor, boolean genericTypeParameter) { if (signatureVisitor != null) { if (genericTypeParameter) { visitAsmType(signatureVisitor, boxType(asmType)); @@ -319,23 +318,8 @@ public class JetTypeMapper { return asmType; } - public static void visitAsmType(SignatureVisitor visitor, Type asmType) { - switch (asmType.getSort()) { - case Type.OBJECT: - visitor.visitClassType(asmType.getInternalName()); - visitor.visitEnd(); - return; - case Type.ARRAY: - SignatureVisitor elementSignatureVisitor = visitor.visitArrayType(); - visitAsmType(elementSignatureVisitor, asmType.getElementType()); - return; - default: - String descriptor = asmType.getDescriptor(); - if (descriptor.length() != 1) { - throw new IllegalStateException(); - } - visitor.visitBaseType(descriptor.charAt(0)); - } + public static void visitAsmType(BothSignatureWriter visitor, Type asmType) { + visitor.writeAsmType(asmType); } public static Type unboxType(final Type type) { @@ -391,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; @@ -456,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(); @@ -489,24 +461,98 @@ public class JetTypeMapper { parameterTypes.add(type); } if (receiverType != null) { - parameterTypes.add(mapType(receiverType, signatureVisitor != null ? signatureVisitor.visitParameterType() : null)); + if (signatureVisitor != null) { + signatureVisitor.writeParameterType(); + } + parameterTypes.add(mapType(receiverType, signatureVisitor)); + if (signatureVisitor != null) { + signatureVisitor.writeParameterTypeEnd(); + } } for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { parameterTypes.add(TYPE_TYPEINFO); if (signatureVisitor != null) { - visitAsmType(signatureVisitor.visitParameterType(), TYPE_TYPEINFO); + signatureVisitor.writeParameterType(); + visitAsmType(signatureVisitor, TYPE_TYPEINFO); + signatureVisitor.writeParameterTypeEnd(); } } } for (ValueParameterDescriptor parameter : parameters) { - Type type = mapType(parameter.getOutType(), signatureVisitor != null ? signatureVisitor.visitParameterType() : null); + if (signatureVisitor != null) { + signatureVisitor.writeParameterType(); + } + Type type = mapType(parameter.getOutType(), signatureVisitor); + if (signatureVisitor != null) { + signatureVisitor.writeParameterTypeEnd(); + } valueParameterTypes.add(type); parameterTypes.add(type); } - Type returnType = f instanceof ConstructorDescriptor ? Type.VOID_TYPE : mapReturnType(f.getReturnType(), signatureVisitor != null ? signatureVisitor.visitReturnType() : null); + Type returnType; + if (f instanceof ConstructorDescriptor) { + returnType = Type.VOID_TYPE; + if (signatureVisitor != null) { + signatureVisitor.writeReturnType(); + visitAsmType(signatureVisitor, Type.VOID_TYPE); + signatureVisitor.writeReturnTypeEnd(); + } + } else { + if (signatureVisitor != null) { + signatureVisitor.writeReturnType(); + returnType = mapReturnType(f.getReturnType(), signatureVisitor); + signatureVisitor.writeReturnTypeEnd(); + } + else { + returnType = mapReturnType(f.getReturnType(), null); + } + } Method method = new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, signatureWriter != null ? signatureWriter.toString() : null); + return new JvmMethodSignature(method, signatureVisitor != null ? signatureVisitor.makeJavaString() : null); + } + + + public void writeFormalTypeParameters(List typeParameters, BothSignatureWriter signatureVisitor) { + if (signatureVisitor == null) { + return; + } + + for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { + writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); + } + } + + private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) { + signatureVisitor.writeFormalTypeParameter(typeParameterDescriptor.getName()); + + classBound: + { + signatureVisitor.writeClassBound(); + + for (JetType jetType : typeParameterDescriptor.getUpperBounds()) { + if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) { + if (!CodegenUtil.isInterface(jetType)) { + mapType(jetType, signatureVisitor); + break classBound; + } + } + } + + // "extends Object" seems to be not optional according to ClassFileFormat-Java5.pdf + } + signatureVisitor.writeClassBoundEnd(); + + for (JetType jetType : typeParameterDescriptor.getUpperBounds()) { + if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) { + if (CodegenUtil.isInterface(jetType)) { + signatureVisitor.writeInterfaceBound(); + mapType(jetType, signatureVisitor); + signatureVisitor.writeInterfaceBoundEnd(); + } + } + } + } public JvmMethodSignature mapSignature(String name, FunctionDescriptor f) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java new file mode 100644 index 00000000000..e866f873f8a --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java @@ -0,0 +1,36 @@ +package org.jetbrains.jet.codegen; + +import java.util.List; + +/** + * @author Stepan Koltsov + */ +public class JvmClassSignature { + private final String name; + private final String superclassName; + private final List interfaces; + private final String genericSignature; + + public JvmClassSignature(String name, String superclassName, List interfaces, String genericSignature) { + this.name = name; + this.superclassName = superclassName; + this.interfaces = interfaces; + this.genericSignature = genericSignature; + } + + public String getName() { + return name; + } + + public String getSuperclassName() { + return superclassName; + } + + public List getInterfaces() { + return interfaces; + } + + public String getGenericSignature() { + return genericSignature; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java index 5bade930733..3dde936fe39 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/StdlibNames.java @@ -27,6 +27,7 @@ public class StdlibNames { public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType"; + public static final String JET_OBJECT_INTERNAL = "jet/JetObject"; public static final String JET_OBJECT_CLASS = "jet.JetObject"; public static final String JET_OBJECT_DESCRIPTOR = "Ljet/JetObject;"; diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java new file mode 100644 index 00000000000..2d1e5d107fc --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.java @@ -0,0 +1,6 @@ +class ExtendsAbstractListT { + { + Mine mine = null; + java.util.List list = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt new file mode 100644 index 00000000000..472c847fd89 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ExtendsAbstractListT.kt @@ -0,0 +1 @@ +abstract class Mine() : java.util.AbstractList() diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java new file mode 100644 index 00000000000..699606e6a43 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.java @@ -0,0 +1,7 @@ + +class PlainExtendsListString { + { + Mine mine = null; + java.util.List list = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt new file mode 100644 index 00000000000..8de577c0bcc --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsListString.kt @@ -0,0 +1 @@ +abstract class Mine : java.util.List diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java new file mode 100644 index 00000000000..5664662764e --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.java @@ -0,0 +1,7 @@ + +class ImplementsMapPP { + { + Mine mine = null; + java.util.Map map = mine; + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt new file mode 100644 index 00000000000..a973a76c33e --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/class/ImplementsMapPP.kt @@ -0,0 +1 @@ +abstract class Mine : java.util.Map diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java new file mode 100644 index 00000000000..72b7170231a --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.java @@ -0,0 +1,8 @@ + +class Question { + // id2 is to prevent java type parameter type inference + static T id2(T p) { return p; } + { + java.util.List s = id2(namespace.id((jet.typeinfo.TypeInfo) null, null)); + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt new file mode 100644 index 00000000000..40dc99ff079 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsListString.kt @@ -0,0 +1,3 @@ +import java.util.List + +fun > id(p: P1) = p diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java new file mode 100644 index 00000000000..f525b5923a5 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.java @@ -0,0 +1,8 @@ + +class Question { + // id2 is to prevent java type parameter type inference + static T id2(T p) { return p; } + { + String s = id2(namespace.id((jet.typeinfo.TypeInfo) null, null)); + } +} diff --git a/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt new file mode 100644 index 00000000000..e360425de59 --- /dev/null +++ b/compiler/testData/compileJavaAgainstKotlin/method/QExtendsString.kt @@ -0,0 +1 @@ +fun id(p: T) = p From af9c364c5c91adbd4488def989eee3211324e323 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:28:49 +0400 Subject: [PATCH 08/22] JetSignatureVisitor and subclasses --- .../jet/codegen/BothSignatureWriter.java | 4 + .../codegen/signature/JetSignatureReader.java | 161 ++++++++++++++ .../signature/JetSignatureVisitor.java | 141 ++++++++++++ .../codegen/signature/JetSignatureWriter.java | 201 ++++++++++++++++++ 4 files changed, 507 insertions(+) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java index e63487fc198..f2cb8838b1d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.signature.JetSignatureWriter; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; @@ -29,6 +30,9 @@ public class BothSignatureWriter { private final SignatureWriter signatureWriter = new SignatureWriter(); private final SignatureVisitor signatureVisitor; + + private final JetSignatureWriter jetSignatureWriter = new JetSignatureWriter(); + private final Mode mode; public BothSignatureWriter(Mode mode) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java new file mode 100644 index 00000000000..6485efde6bf --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java @@ -0,0 +1,161 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureReader + */ +public class JetSignatureReader { + + private final String signature; + + public JetSignatureReader(String signature) { + this.signature = signature; + } + + + public void accept(final JetSignatureVisitor v) { + String signature = this.signature; + int len = signature.length(); + int pos; + char c; + + if (signature.charAt(0) == '<') { + pos = 2; + do { + int end = signature.indexOf(':', pos); + v.visitFormalTypeParameter(signature.substring(pos - 1, end)); + pos = end + 1; + + c = signature.charAt(pos); + if (c == 'L' || c == '[' || c == 'T') { + pos = parseType(signature, pos, v.visitClassBound()); + } + + while ((c = signature.charAt(pos++)) == ':') { + pos = parseType(signature, pos, v.visitInterfaceBound()); + } + } while (c != '>'); + } else { + pos = 0; + } + + if (signature.charAt(pos) == '(') { + pos++; + while (signature.charAt(pos) != ')') { + pos = parseType(signature, pos, v.visitParameterType()); + } + pos = parseType(signature, pos + 1, v.visitReturnType()); + while (pos < len) { + pos = parseType(signature, pos + 1, v.visitExceptionType()); + } + } else { + pos = parseType(signature, pos, v.visitSuperclass()); + while (pos < len) { + pos = parseType(signature, pos, v.visitInterface()); + } + } + } + + + private static int parseType( + final String signature, + int pos, + final JetSignatureVisitor v) + { + char c; + int start, end; + boolean visited, inner; + String name; + + boolean nullable = false; + if (signature.charAt(pos) == '?') { + nullable = true; + pos++; + } + + switch (c = signature.charAt(pos++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + case 'V': + v.visitBaseType(c, nullable); + return pos; + + case '[': + return parseType(signature, pos, v.visitArrayType(nullable)); + + case 'T': + end = signature.indexOf(';', pos); + v.visitTypeVariable(signature.substring(pos, end), nullable); + return end + 1; + + default: // case 'L': + start = pos; + visited = false; + inner = false; + for (;;) { + switch (c = signature.charAt(pos++)) { + case '.': + case ';': + if (!visited) { + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + } + if (c == ';') { + v.visitEnd(); + return pos; + } + start = pos; + visited = false; + inner = true; + break; + + case '<': + name = signature.substring(start, pos - 1); + if (inner) { + v.visitInnerClassType(name, nullable); + } else { + v.visitClassType(name, nullable); + } + visited = true; + top: for (;;) { + switch (c = signature.charAt(pos)) { + case '>': + break top; + case '*': + ++pos; + v.visitTypeArgument(); + break; + case '+': + case '-': + pos = parseType(signature, + pos + 1, + v.visitTypeArgument(c)); + break; + default: + pos = parseType(signature, + pos, + v.visitTypeArgument('=')); + break; + } + } + } + } + } + } + + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java new file mode 100644 index 00000000000..04e1319dd03 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java @@ -0,0 +1,141 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * @author Stepan Koltsov + * + * @see SignatureVisitor + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures + */ +public interface JetSignatureVisitor { + + /** + * Wildcard for an "extends" type argument. + */ + char EXTENDS = '+'; + + /** + * Wildcard for a "super" type argument. + */ + char SUPER = '-'; + + /** + * Wildcard for a normal type argument. + */ + char INSTANCEOF = '='; + + /** + * Visits a formal type parameter. + * + * @param name the name of the formal parameter. + */ + void visitFormalTypeParameter(String name); + + /** + * Visits the class bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the class bound. + */ + JetSignatureVisitor visitClassBound(); + + /** + * Visits an interface bound of the last visited formal type parameter. + * + * @return a non null visitor to visit the signature of the interface bound. + */ + JetSignatureVisitor visitInterfaceBound(); + + /** + * Visits the type of the super class. + * + * @return a non null visitor to visit the signature of the super class + * type. + */ + JetSignatureVisitor visitSuperclass(); + + /** + * Visits the type of an interface implemented by the class. + * + * @return a non null visitor to visit the signature of the interface type. + */ + JetSignatureVisitor visitInterface(); + + /** + * Visits the type of a method parameter. + * + * @return a non null visitor to visit the signature of the parameter type. + */ + JetSignatureVisitor visitParameterType(); + + /** + * Visits the return type of the method. + * + * @return a non null visitor to visit the signature of the return type. + */ + JetSignatureVisitor visitReturnType(); + + /** + * Visits the type of a method exception. + * + * @return a non null visitor to visit the signature of the exception type. + */ + JetSignatureVisitor visitExceptionType(); + + /** + * Visits a signature corresponding to a primitive type. + * + * @param descriptor the descriptor of the primitive type, or 'V' for + * void. + */ + void visitBaseType(char descriptor, boolean nullable); + + /** + * Visits a signature corresponding to a type variable. + * + * @param name the name of the type variable. + */ + void visitTypeVariable(String name, boolean nullable); + + /** + * Visits a signature corresponding to an array type. + * + * @return a non null visitor to visit the signature of the array element + * type. + */ + JetSignatureVisitor visitArrayType(boolean nullable); + + /** + * Starts the visit of a signature corresponding to a class or interface + * type. + * + * @param name the internal name of the class or interface. + */ + void visitClassType(String name, boolean nullable); + + /** + * Visits an inner class. + * + * @param name the local name of the inner class in its enclosing class. + */ + void visitInnerClassType(String name, boolean nullable); + + /** + * Visits an unbounded type argument of the last visited class or inner + * class type. + */ + void visitTypeArgument(); + + /** + * Visits a type argument of the last visited class or inner class type. + * + * @param wildcard '+', '-' or '='. + * @return a non null visitor to visit the signature of the type argument. + */ + JetSignatureVisitor visitTypeArgument(char wildcard); + + /** + * Ends the visit of a signature corresponding to a class or interface type. + */ + void visitEnd(); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java new file mode 100644 index 00000000000..b85d48b3ecc --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java @@ -0,0 +1,201 @@ +package org.jetbrains.jet.codegen.signature; + +import org.objectweb.asm.signature.SignatureWriter; + +/** + * @author Stepan Koltsov + * + * @see SignatureWriter + */ +public class JetSignatureWriter implements JetSignatureVisitor { + + /** + * Buffer used to construct the signature. + */ + private final StringBuffer buf = new StringBuffer(); + + /** + * Indicates if the signature contains formal type parameters. + */ + private boolean hasFormals; + + /** + * Indicates if the signature contains method parameter types. + */ + private boolean hasParameters; + + /** + * Stack used to keep track of class types that have arguments. Each element + * of this stack is a boolean encoded in one bit. The top of the stack is + * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = + * /2. + */ + private int argumentStack; + + /** + * Constructs a new {@link SignatureWriter} object. + */ + public JetSignatureWriter() { + } + + // ------------------------------------------------------------------------ + // Implementation of the SignatureVisitor interface + // ------------------------------------------------------------------------ + + @Override + public void visitFormalTypeParameter(final String name) { + if (!hasFormals) { + hasFormals = true; + buf.append('<'); + } + buf.append(name); + buf.append(':'); + } + + @Override + public JetSignatureWriter visitClassBound() { + return this; + } + + @Override + public JetSignatureWriter visitInterfaceBound() { + buf.append(':'); + return this; + } + + @Override + public JetSignatureWriter visitSuperclass() { + endFormals(); + return this; + } + + @Override + public JetSignatureWriter visitInterface() { + return this; + } + + @Override + public JetSignatureWriter visitParameterType() { + endFormals(); + if (!hasParameters) { + hasParameters = true; + buf.append('('); + } + return this; + } + + @Override + public JetSignatureWriter visitReturnType() { + endFormals(); + if (!hasParameters) { + buf.append('('); + } + buf.append(')'); + return this; + } + + @Override + public JetSignatureWriter visitExceptionType() { + buf.append('^'); + return this; + } + + private void visitNullabe(boolean nullable) { + if (nullable) { + buf.append('?'); + } + } + + @Override + public void visitBaseType(final char descriptor, boolean nullable) { + visitNullabe(nullable); + buf.append(descriptor); + } + + @Override + public void visitTypeVariable(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('T'); + buf.append(name); + buf.append(';'); + } + + @Override + public JetSignatureWriter visitArrayType(boolean nullable) { + visitNullabe(nullable); + buf.append('['); + return this; + } + + @Override + public void visitClassType(final String name, boolean nullable) { + visitNullabe(nullable); + buf.append('L'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitInnerClassType(final String name, boolean nullable) { + endArguments(); + visitNullabe(nullable); + buf.append('.'); + buf.append(name); + argumentStack *= 2; + } + + @Override + public void visitTypeArgument() { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + buf.append('*'); + } + + @Override + public JetSignatureWriter visitTypeArgument(final char wildcard) { + if (argumentStack % 2 == 0) { + ++argumentStack; + buf.append('<'); + } + if (wildcard != '=') { + buf.append(wildcard); + } + return this; + } + + @Override + public void visitEnd() { + endArguments(); + buf.append(';'); + } + + public String toString() { + return buf.toString(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Ends the formal type parameters section of the signature. + */ + private void endFormals() { + if (hasFormals) { + hasFormals = false; + buf.append('>'); + } + } + + /** + * Ends the type arguments of a class or inner class type. + */ + private void endArguments() { + if (argumentStack % 2 != 0) { + buf.append('>'); + } + argumentStack /= 2; + } +} From 676595036b29f0eec7729687a60a8c07f6f06b8f Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:36:06 +0400 Subject: [PATCH 09/22] move StdlibNames to frontend.java module requested by Andrey Breslav --- .../backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java | 2 +- .../org/jetbrains/jet/codegen/ImplementationBodyCodegen.java | 2 +- .../jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java | 1 - .../src/org/jetbrains/jet/lang/resolve/java}/StdlibNames.java | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) rename compiler/{frontend/src/org/jetbrains/jet/lang/resolve => frontend.java/src/org/jetbrains/jet/lang/resolve/java}/StdlibNames.java (96%) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 4edd7db34a4..1f7f2cfca14 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; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 7d8298b489a..421ad544fe4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.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.OverridingUtil; -import org.jetbrains.jet.lang.resolve.StdlibNames; +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; 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..4bafcdc944d 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; 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 96% 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 3dde936fe39..bf268b52f7a 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; From 386d8b1f61430c1ee9a797760528187aff6a9f7f Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:36:11 +0400 Subject: [PATCH 10/22] rename @JetParameter to @JetValueParameter requested by Andrey Breslav --- .../jetbrains/jet/codegen/FunctionCodegen.java | 18 +++++++++--------- .../jetbrains/jet/codegen/JetTypeMapper.java | 2 +- .../resolve/java/JavaDescriptorResolver.java | 6 +++--- .../jet/lang/resolve/java/StdlibNames.java | 10 +++++----- ...etParameter.java => JetValueParameter.java} | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) rename stdlib/src/jet/typeinfo/{JetParameter.java => JetValueParameter.java} (94%) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 1f7f2cfca14..ab951d0e173 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -94,15 +94,15 @@ public class FunctionCodegen { } if(kind == OwnerKind.TRAIT_IMPL) { - AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, "this$self"); + AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, "this$self"); av.visitEnd(); } if(receiverParameter.exists()) { - AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, "this$receiver"); + AnnotationVisitor av = mv.visitParameterAnnotation(start++, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, "this$receiver"); if(receiverParameter.getType().isNullable()) { - av.visit(StdlibNames.JET_PARAMETER_NULLABLE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } av.visitEnd(); } @@ -112,14 +112,14 @@ public class FunctionCodegen { av.visitEnd(); } for(int i = 0; i != paramDescrs.size(); ++i) { - AnnotationVisitor av = mv.visitParameterAnnotation(i + start, StdlibNames.JET_PARAMETER_DESCRIPTOR, true); + AnnotationVisitor av = mv.visitParameterAnnotation(i + start, StdlibNames.JET_VALUE_PARAMETER_DESCRIPTOR, true); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); - av.visit(StdlibNames.JET_PARAMETER_NAME_FIELD, parameterDescriptor.getName()); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD, parameterDescriptor.getName()); if(parameterDescriptor.hasDefaultValue()) { - av.visit(StdlibNames.JET_PARAMETER_HAS_DEFAULT_VALUE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD, true); } if(parameterDescriptor.getOutType().isNullable()) { - av.visit(StdlibNames.JET_PARAMETER_NULLABLE_FIELD, true); + av.visit(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } av.visitEnd(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 750d036d961..d09e0480f0b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -54,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"); 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 4bafcdc944d..d74c6aafd28 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -369,13 +369,13 @@ public class JavaDescriptorResolver { PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); attributes.toString(); - if (annotation.getQualifiedName().equals(StdlibNames.JET_PARAMETER_CLASS)) { - PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_PARAMETER_NAME_FIELD); + if (annotation.getQualifiedName().equals(StdlibNames.JET_VALUE_PARAMETER_CLASS)) { + PsiLiteralExpression nameExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_NAME_FIELD); if (nameExpression != null) { name = (String) nameExpression.getValue(); } - PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_PARAMETER_NULLABLE_FIELD); + PsiLiteralExpression nullableExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD); if (nullableExpression != null) { nullable = (Boolean) nullableExpression.getValue(); } else { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java index bf268b52f7a..214be7c888d 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -7,12 +7,12 @@ 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_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter"; diff --git a/stdlib/src/jet/typeinfo/JetParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java similarity index 94% rename from stdlib/src/jet/typeinfo/JetParameter.java rename to stdlib/src/jet/typeinfo/JetValueParameter.java index bae06e264b1..c40848327db 100644 --- a/stdlib/src/jet/typeinfo/JetParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -12,7 +12,7 @@ import java.lang.annotation.Target; */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) -public @interface JetParameter { +public @interface JetValueParameter { /** * @return name of parameter */ From 0dcd4d682c3265a5926b945eb5b615197f83fab8 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Tue, 13 Dec 2011 18:54:13 +0400 Subject: [PATCH 11/22] more links to specification --- stdlib/src/jet/typeinfo/JetMethod.java | 2 ++ stdlib/src/jet/typeinfo/JetSignature.java | 2 ++ stdlib/src/jet/typeinfo/JetTypeDescriptor.java | 2 ++ stdlib/src/jet/typeinfo/JetTypeParameter.java | 2 ++ stdlib/src/jet/typeinfo/JetTypeProjection.java | 2 ++ stdlib/src/jet/typeinfo/JetValueParameter.java | 2 ++ 6 files changed, 12 insertions(+) diff --git a/stdlib/src/jet/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java index a999ce2f298..edc2199a870 100644 --- a/stdlib/src/jet/typeinfo/JetMethod.java +++ b/stdlib/src/jet/typeinfo/JetMethod.java @@ -11,6 +11,8 @@ import java.lang.annotation.Target; * The fact of receiver presence must be deducted from presence of 'this$receiver' parameter * * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) diff --git a/stdlib/src/jet/typeinfo/JetSignature.java b/stdlib/src/jet/typeinfo/JetSignature.java index ab2455903c2..fe43b49b50d 100644 --- a/stdlib/src/jet/typeinfo/JetSignature.java +++ b/stdlib/src/jet/typeinfo/JetSignature.java @@ -7,6 +7,8 @@ import java.util.*; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Retention(RetentionPolicy.RUNTIME) @interface JetSignature { diff --git a/stdlib/src/jet/typeinfo/JetTypeDescriptor.java b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java index 9d289c97b41..3e2b558ff8f 100644 --- a/stdlib/src/jet/typeinfo/JetTypeDescriptor.java +++ b/stdlib/src/jet/typeinfo/JetTypeDescriptor.java @@ -2,6 +2,8 @@ package jet.typeinfo; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ public @interface JetTypeDescriptor{ // diff --git a/stdlib/src/jet/typeinfo/JetTypeParameter.java b/stdlib/src/jet/typeinfo/JetTypeParameter.java index b57809b98e5..2a748ce97bd 100644 --- a/stdlib/src/jet/typeinfo/JetTypeParameter.java +++ b/stdlib/src/jet/typeinfo/JetTypeParameter.java @@ -9,6 +9,8 @@ import java.lang.annotation.Target; * Annotation for parameters * * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) diff --git a/stdlib/src/jet/typeinfo/JetTypeProjection.java b/stdlib/src/jet/typeinfo/JetTypeProjection.java index 3605c0640e6..fbd90bf7739 100644 --- a/stdlib/src/jet/typeinfo/JetTypeProjection.java +++ b/stdlib/src/jet/typeinfo/JetTypeProjection.java @@ -5,6 +5,8 @@ import java.lang.annotation.RetentionPolicy; /** * @author alex.tkachman + * + * @url http://confluence.jetbrains.net/display/JET/Jet+Signatures */ @Retention(RetentionPolicy.RUNTIME) public @interface JetTypeProjection { diff --git a/stdlib/src/jet/typeinfo/JetValueParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java index c40848327db..3a0a2992ad4 100644 --- a/stdlib/src/jet/typeinfo/JetValueParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.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) From a41d33a56c5c2f3606a0df383dbf65e2794cb90e Mon Sep 17 00:00:00 2001 From: svtk Date: Tue, 13 Dec 2011 19:43:20 +0400 Subject: [PATCH 12/22] KT-351 Distinguish statement and expression positions --- .../jet/lang/diagnostics/Errors.java | 8 ++ .../jet/lang/types/JetStandardClasses.java | 5 + .../BasicExpressionTypingVisitor.java | 22 ++- .../ControlStructureTypingVisitor.java | 45 +++++-- .../lang/types/expressions/DataFlowUtils.java | 30 ++++- .../expressions/ExpressionTypingFacade.java | 4 +- .../ExpressionTypingInternals.java | 2 + .../expressions/ExpressionTypingServices.java | 14 +- .../ExpressionTypingVisitorDispatcher.java | 20 ++- .../ExpressionTypingVisitorForStatements.java | 85 ++++++++---- .../PatternMatchingTypingVisitor.java | 14 +- .../kt510.jet | 0 .../kt607.jet | 0 .../kt609.jet | 0 .../kt610.jet | 0 .../ForWithoutBraces.jet | 0 .../kt770.kt351.kt735_StatementType.jet | 126 ++++++++++++++++++ .../diagnostics/tests/regressions/kt629.jet | 2 +- .../jet/types/JetTypeCheckerTest.java | 6 +- 19 files changed, 318 insertions(+), 65 deletions(-) rename compiler/testData/diagnostics/tests/{control-flow-analysis => controlFlowAnalysis}/kt510.jet (100%) rename compiler/testData/diagnostics/tests/{control-flow-analysis => controlFlowAnalysis}/kt607.jet (100%) rename compiler/testData/diagnostics/tests/{control-flow-analysis => controlFlowAnalysis}/kt609.jet (100%) rename compiler/testData/diagnostics/tests/{control-flow-analysis => controlFlowAnalysis}/kt610.jet (100%) rename compiler/testData/diagnostics/tests/{control => controlStructures}/ForWithoutBraces.jet (100%) create mode 100644 compiler/testData/diagnostics/tests/controlStructures/kt770.kt351.kt735_StatementType.jet 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/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/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index a2898afa2dd..a4b19717143 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 f573e39e79a..4b258197df0 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 @@ -12,8 +12,6 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.calls.TaskPrioritizers; -import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; 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; @@ -54,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); @@ -73,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; } @@ -82,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) { @@ -107,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); @@ -152,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; @@ -181,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(); @@ -419,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..3ed6dc0304e 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 @@ -133,7 +133,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 +159,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 +225,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 +245,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 +271,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) { + 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/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/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 { From 4f16b5da8c2d9e553925929b6a650847bd6f2b20 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 14 Dec 2011 00:58:13 +0400 Subject: [PATCH 13/22] better test --- .../org/jetbrains/jet/ReadClassDataTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 0a84cae970b..7a0fa933747 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; @@ -159,6 +161,20 @@ public class ReadClassDataTest extends UsefulTestCase { Assert.assertEquals(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); } } From b86625a437c66948f8dd8915ea0740c655969f91 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 14 Dec 2011 00:58:17 +0400 Subject: [PATCH 14/22] writing my signatures --- .../jet/codegen/BothSignatureWriter.java | 160 ++++++++++++-- .../jetbrains/jet/codegen/ClosureCodegen.java | 4 +- .../jet/codegen/FunctionCodegen.java | 6 + .../codegen/ImplementationBodyCodegen.java | 90 ++++---- .../jetbrains/jet/codegen/JetTypeMapper.java | 50 +++-- .../jet/codegen/JvmClassSignature.java | 20 +- .../jet/codegen/JvmMethodSignature.java | 18 +- .../resolve/java/JavaDescriptorResolver.java | 27 ++- .../resolve/java/JavaTypeTransformer.java | 15 ++ .../java/JetTypeJetSignatureReader.java | 196 ++++++++++++++++++ .../jet/lang/resolve/java/StdlibNames.java | 2 + .../java/signature/JetSignatureAdapter.java | 79 +++++++ .../java}/signature/JetSignatureReader.java | 13 +- .../java}/signature/JetSignatureVisitor.java | 2 +- .../java}/signature/JetSignatureWriter.java | 2 +- .../jetbrains/jet/lang/types/ErrorUtils.java | 2 +- .../jetbrains/jet/lang/types/JetTypeImpl.java | 2 +- .../org/jetbrains/jet/ReadClassDataTest.java | 2 +- stdlib/src/jet/typeinfo/JetMethod.java | 5 + .../src/jet/typeinfo/JetValueParameter.java | 5 + 20 files changed, 603 insertions(+), 97 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetTypeJetSignatureReader.java create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureAdapter.java rename compiler/{backend/src/org/jetbrains/jet/codegen => frontend.java/src/org/jetbrains/jet/lang/resolve/java}/signature/JetSignatureReader.java (93%) rename compiler/{backend/src/org/jetbrains/jet/codegen => frontend.java/src/org/jetbrains/jet/lang/resolve/java}/signature/JetSignatureVisitor.java (98%) rename compiler/{backend/src/org/jetbrains/jet/codegen => frontend.java/src/org/jetbrains/jet/lang/resolve/java}/signature/JetSignatureWriter.java (98%) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java index f2cb8838b1d..ab2d5de350d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -1,12 +1,17 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.codegen.signature.JetSignatureWriter; +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; /** @@ -27,13 +32,31 @@ public class BothSignatureWriter { 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 final JetSignatureWriter jetSignatureWriter = new JetSignatureWriter(); + 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; @@ -76,20 +99,37 @@ public class BothSignatureWriter { } } } + + 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) { + public void writeAsmType(Type asmType, boolean nullable) { switch (asmType.getSort()) { case Type.OBJECT: - writeClassBegin(asmType.getInternalName()); + writeClassBegin(asmType.getInternalName(), nullable); writeClassEnd(); return; case Type.ARRAY: - writeArrayType(); - writeAsmType(asmType.getElementType()); + writeArrayType(nullable); + writeAsmType(asmType.getElementType(), false); writeArrayEnd(); return; default: @@ -97,20 +137,31 @@ public class BothSignatureWriter { if (descriptor.length() != 1) { throw new IllegalStateException(); } - signatureVisitor().visitBaseType(descriptor.charAt(0)); + writeBaseType(descriptor.charAt(0), nullable); } } - - public void writeClassBegin(String internalName) { + + 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() { + public void writeArrayType(boolean nullable) { push(signatureVisitor().visitArrayType()); + jetSignatureWriter.visitArrayType(nullable); } public void writeArrayEnd() { @@ -119,24 +170,39 @@ public class BothSignatureWriter { public void writeTypeArgument(char c) { push(signatureVisitor().visitTypeArgument(c)); + jetSignatureWriter.visitTypeArgument(c); } public void writeTypeArgumentEnd() { pop(); } - public void writeTypeVariable(final String name) { + 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() { @@ -145,33 +211,75 @@ public class BothSignatureWriter { 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() { - checkTopLevel(); - checkMode(Mode.CLASS); - push(signatureVisitor().visitSuperclass()); + jetSignatureWriter.visitSuperclass(); } public void writeSuperclassEnd() { @@ -186,6 +294,7 @@ public class BothSignatureWriter { checkMode(Mode.CLASS); push(signatureVisitor().visitInterface()); + jetSignatureWriter.visitInterface(); } public void writeInterfaceEnd() { @@ -200,16 +309,31 @@ public class BothSignatureWriter { @Nullable public String makeJavaString() { - if (!visitors.isEmpty()) { + 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 makeKotlinString() { - // TODO: not implemented yet - return null; + 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/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index ab951d0e173..27cea25ce10 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -90,6 +90,9 @@ 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(); } @@ -121,6 +124,9 @@ public class FunctionCodegen { if(parameterDescriptor.getOutType().isNullable()) { 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 421ad544fe4..cd89380cbf5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -61,7 +61,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ? Opcodes.ACC_INTERFACE : 0/*Opcodes.ACC_SUPER*/), signature.getName(), - signature.getGenericSignature(), + signature.getJavaGenericSignature(), signature.getSuperclassName(), signature.getInterfaces().toArray(new String[0]) ); @@ -77,57 +77,55 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { annotationVisitor.visitEnd(); } } - + private JvmClassSignature signature() { - String genericSignature; List superInterfaces; - { - LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); + LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); - BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); - { // type parameters - List typeParameters = descriptor.getTypeConstructor().getParameters(); - typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); - } - - - { // superclass - signatureVisitor.writeSuperclass(); - if (superClassType == null) { - signatureVisitor.writeClassBegin(superClass); - signatureVisitor.writeClassEnd(); - } else { - typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); - } - signatureVisitor.writeSuperclassEnd(); - } - - - { // superinterfaces - superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); - - for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { - JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); - assert superType != null; - ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); - if (CodegenUtil.isInterface(superClassDescriptor)) { - signatureVisitor.writeInterface(); - Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); - signatureVisitor.writeInterfaceEnd(); - superInterfacesLinkedHashSet.add(jvmName.getInternalName()); - } - } - - superInterfaces = new ArrayList(superInterfacesLinkedHashSet); - } - - // TODO: null if class is not generic and does not have generic superclasses - genericSignature = signatureVisitor.makeJavaString(); + { // type parameters + List typeParameters = descriptor.getTypeConstructor().getParameters(); + typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor); } - return new JvmClassSignature(jvmName(), superClass, superInterfaces, genericSignature); + + signatureVisitor.writeSupersStart(); + + { // superclass + signatureVisitor.writeSuperclass(); + if (superClassType == null) { + signatureVisitor.writeClassBegin(superClass, false); + signatureVisitor.writeClassEnd(); + } else { + typeMapper.mapType(superClassType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + } + signatureVisitor.writeSuperclassEnd(); + } + + + { // superinterfaces + superInterfacesLinkedHashSet.add(StdlibNames.JET_OBJECT_INTERNAL); + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.isInterface(superClassDescriptor)) { + signatureVisitor.writeInterface(); + Type jvmName = typeMapper.mapType(superType, OwnerKind.IMPLEMENTATION, signatureVisitor, true); + signatureVisitor.writeInterfaceEnd(); + superInterfacesLinkedHashSet.add(jvmName.getInternalName()); + } + } + + superInterfaces = new ArrayList(superInterfacesLinkedHashSet); + } + + signatureVisitor.writeSupersEnd(); + + return new JvmClassSignature(jvmName(), superClass, superInterfaces, signatureVisitor.makeJavaString(), signatureVisitor.makeKotlinClassSignature()); } private String jvmName() { @@ -324,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 d09e0480f0b..58a60e131b6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -165,13 +165,13 @@ public class JetTypeMapper { @NotNull private Type mapReturnType(final JetType jetType, @Nullable BothSignatureWriter signatureVisitor) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { if (signatureVisitor != null) { - signatureVisitor.writeAsmType(Type.VOID_TYPE); + 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; } @@ -257,7 +257,7 @@ public class JetTypeMapper { JetType memberType = jetType.getArguments().get(0).getType(); if (signatureVisitor != null) { - signatureVisitor.writeArrayType(); + signatureVisitor.writeArrayType(jetType.isNullable()); mapType(memberType, kind, signatureVisitor, true); signatureVisitor.writeArrayEnd(); } @@ -271,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; } @@ -282,7 +282,7 @@ public class JetTypeMapper { Type asmType = Type.getObjectType(name + (kind == OwnerKind.TRAIT_IMPL ? "$$TImpl" : "")); if (signatureVisitor != null) { - signatureVisitor.writeClassBegin(asmType.getInternalName()); + signatureVisitor.writeClassBegin(asmType.getInternalName(), jetType.isNullable()); for (TypeProjection proj : jetType.getArguments()) { // TODO: +- signatureVisitor.writeTypeArgument('='); @@ -298,7 +298,7 @@ public class JetTypeMapper { if (descriptor instanceof TypeParameterDescriptor) { if (signatureVisitor != null) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) jetType.getConstructor().getDeclarationDescriptor(); - signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName()); + signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable()); } return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); @@ -310,16 +310,16 @@ public class JetTypeMapper { 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(BothSignatureWriter visitor, Type asmType) { - visitor.writeAsmType(asmType); + public static void visitAsmType(BothSignatureWriter visitor, Type asmType, boolean nullable) { + visitor.writeAsmType(asmType, nullable); } public static Type unboxType(final Type type) { @@ -469,12 +469,16 @@ public class JetTypeMapper { signatureVisitor.writeParameterTypeEnd(); } } + if (signatureVisitor != null) { + signatureVisitor.writeParametersStart(); + } + for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { parameterTypes.add(TYPE_TYPEINFO); if (signatureVisitor != null) { signatureVisitor.writeParameterType(); - visitAsmType(signatureVisitor, TYPE_TYPEINFO); + visitAsmType(signatureVisitor, TYPE_TYPEINFO, false); signatureVisitor.writeParameterTypeEnd(); } } @@ -490,12 +494,17 @@ public class JetTypeMapper { valueParameterTypes.add(type); parameterTypes.add(type); } + + 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); + visitAsmType(signatureVisitor, Type.VOID_TYPE, false); signatureVisitor.writeReturnTypeEnd(); } } else { @@ -509,7 +518,12 @@ public class JetTypeMapper { } } Method method = new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, signatureVisitor != null ? signatureVisitor.makeJavaString() : null); + if (signatureVisitor == null) { + return new JvmMethodSignature(method, null, null, null); + } else { + return new JvmMethodSignature(method, signatureVisitor.makeJavaString(), + signatureVisitor.makeKotlinSignatures(), signatureVisitor.makeKotlinReturnTypeSignature()); + } } @@ -518,9 +532,11 @@ public class JetTypeMapper { return; } + signatureVisitor.writerFormalTypeParametersStart(); for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); } + signatureVisitor.writeFormalTypeParametersEnd(); } private void writeFormalTypeParameter(TypeParameterDescriptor typeParameterDescriptor, BothSignatureWriter signatureVisitor) { @@ -567,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); } @@ -592,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 @@ -622,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) { @@ -644,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 index e866f873f8a..4eeeaf10542 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmClassSignature.java @@ -1,5 +1,8 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.util.List; /** @@ -9,13 +12,16 @@ public class JvmClassSignature { private final String name; private final String superclassName; private final List interfaces; - private final String genericSignature; + private final String javaGenericSignature; + private final String kotlinGenericSignature; - public JvmClassSignature(String name, String superclassName, List interfaces, String genericSignature) { + public JvmClassSignature(String name, String superclassName, List interfaces, + @Nullable String javaGenericSignature, @Nullable String kotlinGenericSignature) { this.name = name; this.superclassName = superclassName; this.interfaces = interfaces; - this.genericSignature = genericSignature; + this.javaGenericSignature = javaGenericSignature; + this.kotlinGenericSignature = kotlinGenericSignature; } public String getName() { @@ -30,7 +36,11 @@ public class JvmClassSignature { return interfaces; } - public String getGenericSignature() { - return genericSignature; + 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/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 d74c6aafd28..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 @@ -360,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; @@ -383,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, @@ -509,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)) { @@ -520,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/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.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java index 214be7c888d..c6223502385 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/StdlibNames.java @@ -13,6 +13,7 @@ public class StdlibNames { public static final String JET_VALUE_PARAMETER_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,6 +26,7 @@ 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"; 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/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java similarity index 93% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java index 6485efde6bf..cbdebb01b3a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureReader.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureReader.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; @@ -60,6 +60,17 @@ public class JetSignatureReader { } } + 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, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java similarity index 98% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java index 04e1319dd03..e353dd6dbb3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureVisitor.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureVisitor.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureVisitor; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java similarity index 98% rename from compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java rename to compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java index b85d48b3ecc..7e1a7837a08 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JetSignatureWriter.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/signature/JetSignatureWriter.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.codegen.signature; +package org.jetbrains.jet.lang.resolve.java.signature; import org.objectweb.asm.signature.SignatureWriter; 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/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/tests/org/jetbrains/jet/ReadClassDataTest.java b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java index 7a0fa933747..b7ceb359a44 100644 --- a/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java +++ b/compiler/tests/org/jetbrains/jet/ReadClassDataTest.java @@ -158,7 +158,7 @@ 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()); } diff --git a/stdlib/src/jet/typeinfo/JetMethod.java b/stdlib/src/jet/typeinfo/JetMethod.java index edc2199a870..b057014caf2 100644 --- a/stdlib/src/jet/typeinfo/JetMethod.java +++ b/stdlib/src/jet/typeinfo/JetMethod.java @@ -26,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/JetValueParameter.java b/stdlib/src/jet/typeinfo/JetValueParameter.java index 3a0a2992ad4..db0a4f52605 100644 --- a/stdlib/src/jet/typeinfo/JetValueParameter.java +++ b/stdlib/src/jet/typeinfo/JetValueParameter.java @@ -34,4 +34,9 @@ public @interface JetValueParameter { * @return if this parameter has default value */ boolean hasDefaultValue () default false; + + /** + * @return type unless Java type is correct Kotlin type. + */ + String type() default ""; } From 1d4e12abb759d4d9fd602a46b2e7fa7be045cc91 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 14 Dec 2011 01:19:05 +0400 Subject: [PATCH 15/22] make SignatureUtil format closer to JVM --- .../jetbrains/jet/codegen/SignatureUtil.java | 5 +++++ stdlib/src/jet/typeinfo/TypeInfo.java | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) 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/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index a5ad5850ebe..fbba351bcbd 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -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; From 31b536a8e58c7ca1f572e90828ddf82725596825 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 14 Dec 2011 11:03:04 +0400 Subject: [PATCH 16/22] KT-822: Assertion during completion of the subpackage in function --- .../plugin/references/JetSimpleNameReference.java | 12 +++++++++++- idea/testData/completion/basic/SubpackageInFun.kt | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 idea/testData/completion/basic/SubpackageInFun.kt diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 7224322b46e..03fe53b1c8b 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), 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 From 3cf7a44840b5c9a5d17f2bc618e46a7f48582337 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 14 Dec 2011 12:26:57 +0400 Subject: [PATCH 17/22] KT-825 Completion doesn't show overloaded functions --- .../handlers/JetFunctionInsertHandler.java | 4 ++++ .../references/JetSimpleNameReference.java | 4 +++- .../completion/basic/OverloadFunctions.kt | 24 +++++++++++++++++++ .../completion/handlers/SingleBrackets.kt | 17 +++++++++++++ .../handlers/SingleBrackets.kt.after | 17 +++++++++++++ .../jet/completion/JetCompletionTestBase.java | 16 +++++++++++++ .../handlers/FunctionsHandlerTest.java | 8 +++++++ 7 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 idea/testData/completion/basic/OverloadFunctions.kt create mode 100644 idea/testData/completion/handlers/SingleBrackets.kt create mode 100644 idea/testData/completion/handlers/SingleBrackets.kt.after 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 03fe53b1c8b..bb955817b2c 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -148,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; @@ -165,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 @@ -185,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/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/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() + From e8ed53df5f069a2f7a6b65a2c939dd8ac30f2840 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 14 Dec 2011 14:10:58 +0400 Subject: [PATCH 18/22] bug with default parameter value --- .../src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); } From 5e08376e0e6d1e36c0ccd887f8e5635fe4406054 Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 14 Dec 2011 14:27:07 +0400 Subject: [PATCH 19/22] KT-786 Exception on incomplete code with 'when' --- .../jetbrains/jet/lang/types/TypeUtils.java | 1 + .../tests/controlStructures/kt786.jet | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/controlStructures/kt786.jet 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/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 From 9aaf20bc95ec62ecd58573632eb8deaea362a129 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 14 Dec 2011 12:44:07 +0200 Subject: [PATCH 20/22] optimizations for instanceof List<*> --- .../org/jetbrains/jet/codegen/ExpressionCodegen.java | 10 +++++++--- examples/src/benchmarks/FList.kt | 4 ++-- stdlib/src/jet/typeinfo/TypeInfo.java | 10 +++++----- 3 files changed, 14 insertions(+), 10 deletions(-) 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/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/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index fbba351bcbd..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; } From 7e969cf37035b1be1a3e22ebbde3452caded25ff Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Wed, 14 Dec 2011 13:17:57 +0200 Subject: [PATCH 21/22] Binary Boolean.and/or added by patch of Sergey Ignatov --- compiler/frontend/src/jet/Library.jet | 4 ++++ 1 file changed, 4 insertions(+) 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 From b58a986262fe430861d8414b1cf0c7336d05b63c Mon Sep 17 00:00:00 2001 From: svtk Date: Wed, 14 Dec 2011 16:01:23 +0400 Subject: [PATCH 22/22] KT-244 Use dataflow info while resolving variable initializers --- .../jet/lang/resolve/DescriptorResolver.java | 14 ++++---- .../expressions/ExpressionTypingServices.java | 8 +++-- .../ExpressionTypingVisitorForStatements.java | 2 +- .../tests/nullabilityAndAutoCasts/kt244.jet | 34 +++++++++++++++++++ 4 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/kt244.jet 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/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index 3ed6dc0304e..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(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index d4d6cc95afd..56ce116c9df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -85,7 +85,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter)); } - VariableDescriptor propertyDescriptor = context.getDescriptorResolver().resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, property); + VariableDescriptor propertyDescriptor = context.getDescriptorResolver().resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, property, context.dataFlowInfo); JetExpression initializer = property.getInitializer(); if (property.getPropertyTypeRef() != null && initializer != null) { JetType outType = propertyDescriptor.getOutType(); 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