From cf30540247cccd8a5af3d79c73ad0207582917ed Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 18:41:21 +0100 Subject: [PATCH 01/16] failing test diagnostics --- .../jet/compiler/CompileEnvironment.java | 17 +++++++++++++++-- .../org/jetbrains/jet/cli/KotlinCompiler.java | 2 +- .../jet/compiler/CompileEnvironmentTest.java | 5 ++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 607bad3bd4e..52fae2502a4 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -4,7 +4,9 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; import com.intellij.util.Processor; import jet.modules.IModuleBuilder; import jet.modules.IModuleSetBuilder; @@ -40,7 +42,7 @@ public class CompileEnvironment { myEnvironment = new JetCoreEnvironment(myRootDisposable); } - public void setMyErrorStream(PrintStream errorStream) { + public void setErrorStream(PrintStream errorStream) { myErrorStream = errorStream; } @@ -86,7 +88,7 @@ public class CompileEnvironment { myEnvironment.addToClasspath(rtJarPath); } - public static File findActiveRtJar() { + public static File findActiveRtJar(boolean failOnError) { ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); if (systemClassLoader instanceof URLClassLoader) { URLClassLoader loader = (URLClassLoader) systemClassLoader; @@ -100,6 +102,17 @@ public class CompileEnvironment { } } } + if (failOnError) { + throw new CompileEnvironmentException("Could not find rt.jar in system class loader: " + StringUtil.join(loader.getURLs(), new Function() { + @Override + public String fun(URL url) { + return url.toString(); + } + }, ", ")); + } + } + else if (failOnError) { + throw new CompileEnvironmentException("System class loader is not an URLClassLoader: " + systemClassLoader); } return null; } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 22a1f6bc346..55861d76f8a 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -64,7 +64,7 @@ public class KotlinCompiler { String javaHome = System.getenv("JAVA_HOME"); File rtJar; if (javaHome == null) { - rtJar = CompileEnvironment.findActiveRtJar(); + rtJar = CompileEnvironment.findActiveRtJar(false); if(rtJar == null) { System.out.println("JAVA_HOME environment variable needs to be defined"); diff --git a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java index de0a6ecf2fa..bf35a34a8fa 100644 --- a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java +++ b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java @@ -6,6 +6,8 @@ import junit.framework.TestCase; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.parsing.JetParsingTest; +import java.io.File; + /** * @author yole */ @@ -24,7 +26,8 @@ public class CompileEnvironmentTest extends TestCase { } public void testSmoke() { - environment.setJavaRuntime(CompileEnvironment.findActiveRtJar()); + final File activeRtJar = CompileEnvironment.findActiveRtJar(true); + environment.setJavaRuntime(activeRtJar); environment.initializeKotlinRuntime(); final String testDataDir = JetParsingTest.getTestDataDir() + "/compiler/smoke/"; final IModuleSetBuilder setBuilder = environment.loadModuleScript(testDataDir + "Smoke.kts"); From 2911ff95da22d1c65b334bc821177b394bf0894b Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 18:47:40 +0100 Subject: [PATCH 02/16] test also looks for Java under JAVA_HOME --- .../jet/compiler/CompileEnvironment.java | 28 +++++++++++++++ .../org/jetbrains/jet/cli/KotlinCompiler.java | 36 +------------------ .../jet/compiler/CompileEnvironmentTest.java | 2 +- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 52fae2502a4..5945636819d 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -88,6 +88,34 @@ public class CompileEnvironment { myEnvironment.addToClasspath(rtJarPath); } + public static File findRtJar(boolean failOnError) { + String javaHome = System.getenv("JAVA_HOME"); + File rtJar; + if (javaHome == null) { + rtJar = findActiveRtJar(failOnError); + + if(rtJar == null && failOnError) { + throw new CompileEnvironmentException("JAVA_HOME environment variable needs to be defined"); + } + } + else { + rtJar = findRtJar(javaHome); + } + + if ((rtJar == null || !rtJar.exists()) && failOnError) { + throw new CompileEnvironmentException("No rt.jar found under JAVA_HOME=" + javaHome); + } + return rtJar; + } + + private static File findRtJar(String javaHome) { + File rtJar = new File(javaHome, "jre/lib/rt.jar"); + if (rtJar.exists()) { + return rtJar; + } + return null; + } + public static File findActiveRtJar(boolean failOnError) { ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); if (systemClassLoader instanceof URLClassLoader) { diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 55861d76f8a..3de270c6583 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -5,8 +5,6 @@ import com.sampullara.cli.Argument; import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.CompileEnvironmentException; -import java.io.File; - /** * @author yole * @author alex.tkachman @@ -38,11 +36,8 @@ public class KotlinCompiler { CompileEnvironment environment = new CompileEnvironment(); - File rtJar = initJdk(); - if (rtJar == null) return; - try { - environment.setJavaRuntime(rtJar); + environment.setJavaRuntime(CompileEnvironment.findRtJar(true)); if (!environment.initializeKotlinRuntime()) { System.out.println("No runtime library found"); return; @@ -60,33 +55,4 @@ public class KotlinCompiler { } } - private static File initJdk() { - String javaHome = System.getenv("JAVA_HOME"); - File rtJar; - if (javaHome == null) { - rtJar = CompileEnvironment.findActiveRtJar(false); - - if(rtJar == null) { - System.out.println("JAVA_HOME environment variable needs to be defined"); - return null; - } - } - else { - rtJar = findRtJar(javaHome); - } - - if (rtJar == null || !rtJar.exists()) { - System.out.print("No rt.jar found under JAVA_HOME=" + javaHome); - return null; - } - return rtJar; - } - - private static File findRtJar(String javaHome) { - File rtJar = new File(javaHome, "jre/lib/rt.jar"); - if (rtJar.exists()) { - return rtJar; - } - return null; - } } diff --git a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java index bf35a34a8fa..da76a194917 100644 --- a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java +++ b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java @@ -26,7 +26,7 @@ public class CompileEnvironmentTest extends TestCase { } public void testSmoke() { - final File activeRtJar = CompileEnvironment.findActiveRtJar(true); + final File activeRtJar = CompileEnvironment.findRtJar(true); environment.setJavaRuntime(activeRtJar); environment.initializeKotlinRuntime(); final String testDataDir = JetParsingTest.getTestDataDir() + "/compiler/smoke/"; From 8540d60ce17941be5b389f2dd8a2f4e7709ec775 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 19:03:29 +0100 Subject: [PATCH 03/16] some more coverage --- .../jet/compiler/CompileEnvironment.java | 17 +++++++++--- .../jet/compiler/CompileEnvironmentTest.java | 27 ++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 5945636819d..cd92630c416 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -10,6 +10,7 @@ import com.intellij.util.Function; import com.intellij.util.Processor; import jet.modules.IModuleBuilder; import jet.modules.IModuleSetBuilder; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GeneratedClassLoader; @@ -154,7 +155,12 @@ public class CompileEnvironment { final String directory = new File(moduleFile).getParent(); for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory); - writeToJar(moduleFactory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); + final String path = new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); + try { + writeToJar(moduleFactory, new FileOutputStream(path), null, true); + } catch (FileNotFoundException e) { + throw new CompileEnvironmentException("Invalid jar path " + path, e); + } } } @@ -232,7 +238,7 @@ public class CompileEnvironment { return new File(PathManager.getResourceRoot(CompileEnvironment.class, "/org/jetbrains/jet/compiler/CompileEnvironment.class")).getParentFile().getParentFile().getParent(); } - public static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) { + public static void writeToJar(ClassFileFactory factory, final OutputStream fos, @Nullable String mainClass, boolean includeRuntime) { try { Manifest manifest = new Manifest(); final Attributes mainAttributes = manifest.getMainAttributes(); @@ -241,7 +247,6 @@ public class CompileEnvironment { if (mainClass != null) { mainAttributes.putValue("Main-Class", mainClass); } - FileOutputStream fos = new FileOutputStream(jar); JarOutputStream stream = new JarOutputStream(fos, manifest); try { for (String file : factory.files()) { @@ -327,7 +332,11 @@ public class CompileEnvironment { ClassFileFactory factory = session.generate(); if (jar != null) { - writeToJar(factory, jar, mainClass, true); + try { + writeToJar(factory, new FileOutputStream(jar), mainClass, true); + } catch (FileNotFoundException e) { + throw new CompileEnvironmentException("Invalid jar path " + jar, e); + } } else if (outputDir != null) { writeToOutputDirectory(factory, outputDir); diff --git a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java index da76a194917..4b01efe9efd 100644 --- a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java +++ b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java @@ -6,7 +6,14 @@ import junit.framework.TestCase; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.parsing.JetParsingTest; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; /** * @author yole @@ -25,7 +32,7 @@ public class CompileEnvironmentTest extends TestCase { super.tearDown(); } - public void testSmoke() { + public void testSmoke() throws IOException { final File activeRtJar = CompileEnvironment.findRtJar(true); environment.setJavaRuntime(activeRtJar); environment.initializeKotlinRuntime(); @@ -36,5 +43,23 @@ public class CompileEnvironmentTest extends TestCase { final ClassFileFactory factory = environment.compileModule(moduleBuilder, testDataDir); assertNotNull(factory); assertNotNull(factory.asBytes("Smoke/namespace.class")); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CompileEnvironment.writeToJar(factory, baos, null, false); + JarInputStream is = new JarInputStream(new ByteArrayInputStream(baos.toByteArray())); + final List entries = listEntries(is); + assertTrue(entries.contains("Smoke/namespace.class")); + } + + private List listEntries(JarInputStream is) throws IOException { + List entries = new ArrayList(); + while (true) { + final JarEntry jarEntry = is.getNextJarEntry(); + if (jarEntry == null) { + break; + } + entries.add(jarEntry.getName()); + } + return entries; } } From 4012fc8a5f908428e6750c56e2de6d1fa4c5b5d0 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 3 Nov 2011 19:05:58 +0100 Subject: [PATCH 04/16] netty server example --- examples/src/netty/netty.kt | 141 ++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 examples/src/netty/netty.kt diff --git a/examples/src/netty/netty.kt b/examples/src/netty/netty.kt new file mode 100644 index 00000000000..4068072d7ec --- /dev/null +++ b/examples/src/netty/netty.kt @@ -0,0 +1,141 @@ +import java.util.concurrent.Executors +import java.net.InetSocketAddress +import java.net.URLDecoder +import java.io.* + +import org.jboss.netty.bootstrap.ServerBootstrap +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory +import org.jboss.netty.channel.* +import org.jboss.netty.handler.codec.http.* +import org.jboss.netty.handler.stream.ChunkedWriteHandler +import org.jboss.netty.handler.codec.frame.TooLongFrameException +import org.jboss.netty.buffer.ChannelBuffers +import org.jboss.netty.util.CharsetUtil +import org.jboss.netty.handler.codec.http.HttpResponseStatus.* + +import netty.* +import jlstring.* + +namespace jlstring { + fun String.replace(c: Char, by: Char) : String = (this as java.lang.String).replace(c, by) as String + + fun String.contains(s: String) : Boolean = (this as java.lang.String).contains(s as java.lang.CharSequence) + + fun java.lang.String.plus(s: Any?) : String = (this as String) + s.toString() +} + +namespace netty { + fun ChannelPipeline.with(op: fun ChannelPipeline.() ) : ChannelPipeline { + this.op() + return this + } + + fun HttpResponse.set(header: String, value: Any?) : Unit { + setHeader(header, value) + } + + fun HttpResponse.setContent(content: Any?) : Unit { + setContent(ChannelBuffers.copiedBuffer(content.toString() as java.lang.String, CharsetUtil.UTF_8)) + } + + fun ChannelHandlerContext.sendError(status: HttpResponseStatus?) { + val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, status) + response["Content-Type"] = "text/plain; charset=UTF-8" + response.setContent("Failure: " + status.toString() + "\r\n") + + // Close the connection as soon as the error message is sent. + this.getChannel()?.write(response)?.addListener(ChannelFutureListener.CLOSE) + } + + fun String.decodeURI(encoding : String) : String? { + try { + return URLDecoder.decode(this, encoding) + } + catch (e : UnsupportedEncodingException) { + return null + } + } + + fun String.sanitizeUri() : String? { + val path = decodeURI("UTF-8") ?: decodeURI("ISO-8859-1") + if (path == null) + throw Error() + + val localizedPath : String = path.replace('/', File.separatorChar) + return if (localizedPath.contains(File.separator + ".") || + localizedPath.contains("." + File.separator) || + localizedPath.startsWith(".") || endsWith(".")) + null + else + localizedPath + } + + class StandardPipelineFactory(val config: fun ChannelPipeline.():Unit) : ChannelPipelineFactory { + override fun getPipeline() : ChannelPipeline { + val pipeline = DefaultChannelPipeline().with { + addLast("decoder", HttpRequestDecoder()) + addLast("aggregator", HttpChunkAggregator(65536)) + addLast("encoder", HttpResponseEncoder()) + addLast("chunkedWriter", ChunkedWriteHandler()) + } + pipeline.config () // can not move it inside with{} because of codegen bug + return pipeline + } + } + + fun ServerBootstrap.configPipeline(config: fun ChannelPipeline.(): Unit) = + setPipelineFactory( + StandardPipelineFactory(config) + ) +} + +fun main(args : Array) { + val bootstrap = ServerBootstrap( + NioServerSocketChannelFactory( + Executors.newCachedThreadPool(), + Executors.newCachedThreadPool() + ) + ) + bootstrap.configPipeline { + addLast("handler", HttpStaticFileServerHandler(args[0])) + } + bootstrap.bind(InetSocketAddress(8080)) +} + +class HttpStaticFileServerHandler(val rootDir: String) : SimpleChannelUpstreamHandler() { + + fun messageReceived(ctx : ChannelHandlerContext, e : MessageEvent) { + val request = e.getMessage() as HttpRequest + if (request.getMethod() != HttpMethod.GET) { + ctx.sendError(METHOD_NOT_ALLOWED); + return; + } + + val path = request.getUri()?.sanitizeUri() + if (path == null) { + ctx.sendError(FORBIDDEN); + return; + } + + val file = File(rootDir + File.separator + path) + if (file.isHidden() || !file.exists()) { + ctx.sendError(NOT_FOUND) + return + } + if (!file.isFile()) { + ctx.sendError(FORBIDDEN) + return + } + + var raf = RandomAccessFile(file, "r") + + val fileLength = raf.length() + + val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, OK) + response["Content-Length"] = fileLength + + val ch = e.getChannel() + ch?.write(response) + ch?.write(DefaultFileRegion(raf.getChannel(), 0, fileLength)) + } +} From 73292bd4d682ff96a2178a8546cda653153241e3 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 22:23:26 +0300 Subject: [PATCH 05/16] Supporting function literals as selectors --- .../jet/lang/diagnostics/Errors.java | 2 ++ .../jet/lang/psi/JetCallExpression.java | 22 +++++++++++++++++ .../jet/lang/resolve/calls/CallResolver.java | 3 ++- .../BasicExpressionTypingVisitor.java | 3 +-- .../quick/FunctionCalleeExpressions.jet | 24 ++++++++++++++++++- 5 files changed, 50 insertions(+), 4 deletions(-) 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 fbec7d4bf64..6a0a441497f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -228,6 +228,8 @@ public interface Errors { SimpleDiagnosticFactory SUPERTYPE_APPEARS_TWICE = SimpleDiagnosticFactory.create(ERROR, "A supertype appears twice"); SimpleDiagnosticFactory FINAL_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "This type is final, so it cannot be inherited from"); + ParameterizedDiagnosticFactory1 ILLEGAL_SELECTOR = ParameterizedDiagnosticFactory1.create(ERROR, "Expression ''{0}'' cannot be a selector (occur after a dot)"); + SimpleDiagnosticFactory REF_PARAMETER_WITH_VAL_OR_VAR = SimpleDiagnosticFactory.create(ERROR, "'val' and 'var' are not allowed on ref-parameters"); SimpleDiagnosticFactory VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION = SimpleDiagnosticFactory.create(ERROR, "A type annotation is required on a value parameter"); SimpleDiagnosticFactory BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = SimpleDiagnosticFactory.create(ERROR, "'break' and 'continue' are only allowed inside a loop"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java index 79eef89077e..3d208f266a2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java @@ -1,6 +1,8 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -46,6 +48,26 @@ public class JetCallExpression extends JetExpression implements JetCallElement { @Override @NotNull public List getFunctionLiteralArguments() { + JetExpression calleeExpression = getCalleeExpression(); + if (calleeExpression instanceof JetFunctionLiteralExpression) { + List result = new SmartList(); + ASTNode treeNext = calleeExpression.getNode().getTreeNext(); + while (treeNext != null) { + PsiElement psi = treeNext.getPsi(); + if (psi instanceof JetFunctionLiteralExpression) { + result.add((JetFunctionLiteralExpression) psi); + } + else if (psi instanceof JetLabelQualifiedExpression) { + JetLabelQualifiedExpression labelQualifiedExpression = (JetLabelQualifiedExpression) psi; + JetExpression labeledExpression = labelQualifiedExpression.getLabeledExpression(); + if (labeledExpression instanceof JetFunctionLiteralExpression) { + result.add(labeledExpression); + } + } + treeNext = treeNext.getTreeNext(); + } + return result; + } return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL_EXPRESSION); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 231bf7a3e0f..707d4d3c2df 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -187,9 +187,10 @@ public class CallResolver { return null; } - FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.emptyList(), "for expression " + calleeExpression.getText()); + FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.emptyList(), "[for expression " + calleeExpression.getText() + "]"); FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType); ResolvedCallImpl resolvedCall = ResolvedCallImpl.create(functionDescriptor); + resolvedCall.setReceiverArgument(call.getExplicitReceiver()); prioritizedTasks = Collections.singletonList(new ResolutionTask( Collections.singleton(resolvedCall), call, dataFlowInfo)); functionReference = new JetReferenceExpression(calleeExpression.getNode()) { 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 2255ebe885d..f00ecc3cce7 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 @@ -525,8 +525,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } } else { - // TODO : not a simple name -> resolve in scope, expect property type or a function type - context.trace.report(UNSUPPORTED.on(selectorExpression, "getSelectorReturnType")); + context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText())); } return null; } diff --git a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet index 581493762d3..271e8533305 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet @@ -47,4 +47,26 @@ fun main(args : Array) { 1() 1{} 1(){} -} \ No newline at end of file +} + +fun f() : fun Int.() : Unit = {} + +fun main1(args : Array) { + 1.{Int.() => 1}(); + {1}() + {(x : Int) => x}(1) + 1.{Int.(x : Int) => x}(1) + @l{1}() + 1.({Int.() => 1})() + 1.(f())() + 1.if(true){f()}else{f()}() + 1.if(true){Int.() => 1}else{f()}() + 1.if(true){Int.() => 1}else{Int.() => 1}() + + 1."sdf"() + + 1."sdf" + 1.{} + 1.if (true) {} +} + From 1d2efea0a4b2a2575880cb98959d9b731260069b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 22:38:01 +0300 Subject: [PATCH 06/16] KT-439 Support labeled function lliterals in call arguments --- .../jet/lang/psi/JetCallExpression.java | 32 +++++++++++-------- .../quick/regressions/kt439.jet | 7 ++++ 2 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt439.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java index 3d208f266a2..987a7481529 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetCallExpression.java @@ -6,6 +6,7 @@ import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; import java.util.Collections; import java.util.List; @@ -49,26 +50,31 @@ public class JetCallExpression extends JetExpression implements JetCallElement { @NotNull public List getFunctionLiteralArguments() { JetExpression calleeExpression = getCalleeExpression(); + ASTNode node; if (calleeExpression instanceof JetFunctionLiteralExpression) { - List result = new SmartList(); - ASTNode treeNext = calleeExpression.getNode().getTreeNext(); - while (treeNext != null) { - PsiElement psi = treeNext.getPsi(); - if (psi instanceof JetFunctionLiteralExpression) { - result.add((JetFunctionLiteralExpression) psi); - } - else if (psi instanceof JetLabelQualifiedExpression) { - JetLabelQualifiedExpression labelQualifiedExpression = (JetLabelQualifiedExpression) psi; - JetExpression labeledExpression = labelQualifiedExpression.getLabeledExpression(); + node = calleeExpression.getNode().getTreeNext(); + } + else { + node = getNode().getFirstChildNode(); + } + List result = new SmartList(); + while (node != null) { + PsiElement psi = node.getPsi(); + if (psi instanceof JetFunctionLiteralExpression) { + result.add((JetFunctionLiteralExpression) psi); + } + else if (psi instanceof JetPrefixExpression) { + JetPrefixExpression prefixExpression = (JetPrefixExpression) psi; + if (JetTokens.LABELS.contains(prefixExpression.getOperationSign().getReferencedNameElementType())) { + JetExpression labeledExpression = prefixExpression.getBaseExpression(); if (labeledExpression instanceof JetFunctionLiteralExpression) { result.add(labeledExpression); } } - treeNext = treeNext.getTreeNext(); } - return result; + node = node.getTreeNext(); } - return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL_EXPRESSION); + return result; } @Override diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt439.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt439.jet new file mode 100644 index 00000000000..49bd3b8b550 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt439.jet @@ -0,0 +1,7 @@ +// KT-439 Support labeled function lliterals in call arguments + +inline fun run1(body : fun() : T) : T = body() + +fun main1(args : Array) { + run1 @l{ 1 } // should not be an error +} From fbf49391b8dd617ae6b289b2e72866d9b90aeca0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 3 Nov 2011 22:44:18 +0300 Subject: [PATCH 07/16] Formatting --- stdlib/ktSrc/StandardLibrary.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index bd0fab6b7d9..adc863dd482 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -13,10 +13,7 @@ namespace io { fun print(message : Float) { System.out?.print(message) } fun print(message : Double) { System.out?.print(message) } - fun println(message : Any?) { - System.out?.println(message) - } - + fun println(message : Any?) { System.out?.println(message) } fun println(message : Int) { System.out?.println(message) } fun println(message : Long) { System.out?.println(message) } fun println(message : Byte) { System.out?.println(message) } From 750e2e25f00d0b0b05ba14e10677b4cf01782d34 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 20:44:21 +0100 Subject: [PATCH 08/16] diagnostics for missing JetPsiCheckerTest --- .../org/jetbrains/jet/checkers/JetPsiCheckerTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java index 608022b4a54..ca1f7bb8e14 100644 --- a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java @@ -55,13 +55,17 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase { public static Test suite() { TestSuite suite = new TestSuite(); - suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, new JetTestCaseBuilder.NamedTestFactory() { + final TestSuite checkerSuite = JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override public Test createTest(@NotNull String dataPath, @NotNull String name) { return new JetPsiCheckerTest(dataPath, name); } - })); + }); + if (checkerSuite.countTestCases() == 0) { + throw new RuntimeException("didn't find any testcases under /checker/"); + } + suite.addTest(checkerSuite); suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/regression/", false, new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override From 2f191d3c43a6c3ec43574c0e71fd076b2adc9de9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 3 Nov 2011 21:15:32 +0100 Subject: [PATCH 09/16] avoid nesting of testsuites (hopefully it will help TeamCity report tests correctly) --- .../org/jetbrains/jet/JetTestCaseBuilder.java | 10 +++++++--- .../jet/checkers/JetPsiCheckerTest.java | 16 ++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java index 0698cdbac4b..0fcc6c82e8c 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java +++ b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java @@ -16,7 +16,7 @@ import java.util.List; * @author abreslav */ public abstract class JetTestCaseBuilder { - private static FilenameFilter emptyFilter = new FilenameFilter() { + public static FilenameFilter emptyFilter = new FilenameFilter() { @Override public boolean accept(File file, String name) { return true; @@ -43,6 +43,11 @@ public abstract class JetTestCaseBuilder { @NotNull public static TestSuite suiteForDirectory(String baseDataDir, @NotNull final String dataPath, boolean recursive, final FilenameFilter filter, @NotNull NamedTestFactory factory) { TestSuite suite = new TestSuite(dataPath); + appendTestsInDirectory(baseDataDir, dataPath, recursive, filter, factory, suite); + return suite; + } + + public static void appendTestsInDirectory(String baseDataDir, String dataPath, boolean recursive, final FilenameFilter filter, NamedTestFactory factory, TestSuite suite) { final String extensionJet = ".jet"; final String extensionKt = ".kt"; final FilenameFilter extensionFilter = new FilenameFilter() { @@ -76,7 +81,7 @@ public abstract class JetTestCaseBuilder { List subdirs = Arrays.asList(files); Collections.sort(subdirs); for (File subdir : subdirs) { - suite.addTest(suiteForDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, filter, factory)); + appendTestsInDirectory(baseDataDir, dataPath + "/" + subdir.getName(), recursive, filter, factory, suite); } } List files = Arrays.asList(dir.listFiles(resultFilter)); @@ -87,6 +92,5 @@ public abstract class JetTestCaseBuilder { String extension = fileName.endsWith(extensionJet) ? extensionJet : extensionKt; suite.addTest(factory.createTest(dataPath, fileName.substring(0, fileName.length() - extension.length()))); } - return suite; } } diff --git a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java index ca1f7bb8e14..c99444a9fb9 100644 --- a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java @@ -55,31 +55,27 @@ public class JetPsiCheckerTest extends LightDaemonAnalyzerTestCase { public static Test suite() { TestSuite suite = new TestSuite(); - final TestSuite checkerSuite = JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, new JetTestCaseBuilder.NamedTestFactory() { + JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override public Test createTest(@NotNull String dataPath, @NotNull String name) { return new JetPsiCheckerTest(dataPath, name); } - }); - if (checkerSuite.countTestCases() == 0) { - throw new RuntimeException("didn't find any testcases under /checker/"); - } - suite.addTest(checkerSuite); - suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/regression/", false, new JetTestCaseBuilder.NamedTestFactory() { + }, suite); + JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/regression/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override public Test createTest(@NotNull String dataPath, @NotNull String name) { return new JetPsiCheckerTest(dataPath, name); } - })); - suite.addTest(JetTestCaseBuilder.suiteForDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/infos/", false, new JetTestCaseBuilder.NamedTestFactory() { + }, suite); + JetTestCaseBuilder.appendTestsInDirectory(PluginTestCaseBase.getTestDataPathBase(), "/checker/infos/", false, JetTestCaseBuilder.emptyFilter, new JetTestCaseBuilder.NamedTestFactory() { @NotNull @Override public Test createTest(@NotNull String dataPath, @NotNull String name) { return new JetPsiCheckerTest(dataPath, name).setCheckInfos(true); } - })); + }, suite); return suite; } } From da3936ddd93e345890bbf9cfe18bf20fae94b4a0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 4 Nov 2011 14:40:45 +0300 Subject: [PATCH 10/16] ResolvedCall recorder for the correct element --- .../jet/lang/resolve/calls/CallResolver.java | 21 ++++++++++++---- .../lang/resolve/calls/JetFakeReference.java | 24 +++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/JetFakeReference.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 707d4d3c2df..608273bdc96 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -177,7 +177,7 @@ public class CallResolver { else if (calleeExpression != null) { // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) ExpressionTypingServices typingServices = new ExpressionTypingServices(semanticServices, trace); - JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE);// We are actually expecting a function, but there seems to be no easy way of expressing this + JetType calleeType = typingServices.safeGetType(scope, calleeExpression, NO_EXPECTED_TYPE); // We are actually expecting a function, but there seems to be no easy way of expressing this if (!JetStandardClasses.isFunctionType(calleeType)) { checkTypesWithNoCallee(trace, scope, call); @@ -193,8 +193,11 @@ public class CallResolver { resolvedCall.setReceiverArgument(call.getExplicitReceiver()); prioritizedTasks = Collections.singletonList(new ResolutionTask( Collections.singleton(resolvedCall), call, dataFlowInfo)); - functionReference = new JetReferenceExpression(calleeExpression.getNode()) { - }; + + // strictly speaking, this is a hack: + // we need to pass a reference, but there's no reference in the PSI, + // so we wrap what we have into a fake reference and pass it on (unwrap on the other end) + functionReference = new JetFakeReference(calleeExpression); } else { checkTypesWithNoCallee(trace, scope, call); @@ -239,9 +242,17 @@ public class CallResolver { // trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor()); // } // else { - trace.record(REFERENCE_TARGET, reference, descriptor); // } - trace.record(RESOLVED_CALL, reference, resolvedCall); + if (reference instanceof JetFakeReference) { + // This means that the callable being invoked was represented by an expression + // rather than a reference expression + JetFakeReference fakeReference = (JetFakeReference) reference; + trace.record(RESOLVED_CALL, fakeReference.getActualElement(), resolvedCall); + } + else { + trace.record(RESOLVED_CALL, reference, resolvedCall); + trace.record(REFERENCE_TARGET, reference, descriptor); + } } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/JetFakeReference.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/JetFakeReference.java new file mode 100644 index 00000000000..73d372d2868 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/JetFakeReference.java @@ -0,0 +1,24 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetReferenceExpression; + +/** + * + * This class is used to wrap an expression that occurs in a reference position, such as a function literal, into a reference expression + * + * @author abreslav + */ +public class JetFakeReference extends JetReferenceExpression { + private final JetElement actualElement; + + public JetFakeReference(@NotNull JetElement actualElement) { + super(actualElement.getNode()); + this.actualElement = actualElement; + } + + public JetElement getActualElement() { + return actualElement; + } +} From b00c2272d4d34c813a3ffa73fface34971fbcbf0 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 4 Nov 2011 14:52:32 +0300 Subject: [PATCH 11/16] Error reporting improved on function calls --- .../jet/lang/resolve/calls/CallResolver.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 608273bdc96..86fa17c15b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -483,23 +483,18 @@ public class CallResolver { else { // Explicit type arguments passed - for (JetTypeProjection typeArgument : jetTypeArguments) { - if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { -// temporaryTrace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning - temporaryTrace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeArgument)); + List typeArguments = new ArrayList(); + for (JetTypeProjection projection : jetTypeArguments) { + if (projection.getProjectionKind() != JetProjectionKind.NONE) { + temporaryTrace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection)); + } + JetTypeReference typeReference = projection.getTypeReference(); + if (typeReference != null) { + typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference)); } } - int expectedTypeArgumentCount = candidate.getTypeParameters().size(); if (expectedTypeArgumentCount == jetTypeArguments.size()) { - List typeArguments = new ArrayList(); - for (JetTypeProjection projection : jetTypeArguments) { - // TODO : check that there's no projection - JetTypeReference typeReference = projection.getTypeReference(); - if (typeReference != null) { - typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference)); - } - } checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, temporaryTrace); From b15af315c4432e18c8075d52e9ba63116a71d660 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 4 Nov 2011 14:52:42 +0300 Subject: [PATCH 12/16] Tests for errors on literal callees --- .../quick/FunctionCalleeExpressions.jet | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet index 271e8533305..15acd8ec22c 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/FunctionCalleeExpressions.jet @@ -70,3 +70,13 @@ fun main1(args : Array) { 1.if (true) {} } +fun test() { + {(x : Int) => 1}() + {Int.() => 1}() + "sd".{Int.() => 1}() + val i : Int? = null + i.{Int.() => 1}() + {}() + 1?.{Int.() => 1}() + 1.{}() +} \ No newline at end of file From 2755fb8538fd44f7136f4d0549996219e8cbeff3 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 4 Nov 2011 14:53:03 +0300 Subject: [PATCH 13/16] Test for function call with projection type arguments --- .../quick/ProjectionOnFunctionArgumentErrror.jet | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/ProjectionOnFunctionArgumentErrror.jet diff --git a/compiler/testData/checkerWithErrorTypes/quick/ProjectionOnFunctionArgumentErrror.jet b/compiler/testData/checkerWithErrorTypes/quick/ProjectionOnFunctionArgumentErrror.jet new file mode 100644 index 00000000000..d509e83f5ad --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/ProjectionOnFunctionArgumentErrror.jet @@ -0,0 +1,4 @@ +fun test() { + fun foo(){} + foo<in Int>() +} \ No newline at end of file From df87493e4d1debb1aa4d82e07f3ef55156b0bc95 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 4 Nov 2011 13:11:41 +0100 Subject: [PATCH 14/16] initial super.property --- .../jetbrains/jet/codegen/ClosureCodegen.java | 2 +- .../jet/codegen/ExpressionCodegen.java | 45 +++++++++++----- .../codegen/ImplementationBodyCodegen.java | 4 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 19 +++++-- .../jet/codegen/NamespaceCodegen.java | 4 +- .../jet/codegen/PropertyCodegen.java | 21 +++++--- .../org/jetbrains/jet/codegen/StackValue.java | 30 +++++++---- .../jet/codegen/TraitImplBodyCodegen.java | 2 +- .../testData/codegen/super/basicproperty.jet | 22 ++++++++ .../testData/codegen/super/traitproperty.jet | 29 +++++++++++ .../jet/codegen/FunctionGenTest.java | 51 +++++++++++++++++++ .../jetbrains/jet/codegen/SuperGenTest.java | 13 +++++ 12 files changed, 204 insertions(+), 38 deletions(-) create mode 100644 compiler/testData/codegen/super/basicproperty.jet create mode 100644 compiler/testData/codegen/super/traitproperty.jet create mode 100644 compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 33eaf4ec4e0..9217feb4cce 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -69,7 +69,7 @@ public class ClosureCodegen extends FunctionOrClosureCodegen { signatureWriter.visitEnd(); cv.defineClass(V1_6, - ACC_PUBLIC, + ACC_PUBLIC/*|ACC_SUPER*/, name, null, funClass, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 545e9f9a791..ec5777f8558 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -128,6 +128,23 @@ public class ExpressionCodegen extends JetVisitor { throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented"); } + @Override + public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) { + throw new UnsupportedOperationException("Codegen for named functions is not yet implemented"); + } + + @Override + public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) { +// final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); +// if (descriptor instanceof ClassDescriptor) { +// return generateThisOrOuter((ClassDescriptor) descriptor); +// } +// else { +// return thisExpression(); +// } + return StackValue.none(); + } + @Override public StackValue visitParenthesizedExpression(JetParenthesizedExpression expression, StackValue receiver) { return genQualified(receiver, expression.getExpression()); @@ -285,7 +302,7 @@ public class ExpressionCodegen extends JetVisitor { // if(hND != null) // invokeFunctionNoParams(hND, Type.BOOLEAN_TYPE, v); // else - intermediateValueForProperty((PropertyDescriptor) hasNextDescriptor, false, false).put(Type.BOOLEAN_TYPE, v); + intermediateValueForProperty((PropertyDescriptor) hasNextDescriptor, false, false, false).put(Type.BOOLEAN_TYPE, v); } v.ifeq(end); @@ -793,16 +810,17 @@ public class ExpressionCodegen extends JetVisitor { } else { boolean isStatic = container instanceof NamespaceDescriptorImpl; - final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; + final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL ; JetExpression r = getReceiverForSelector(expression); final boolean forceInterface = r != null && !(r instanceof JetThisExpression); - final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface); + final boolean isSuper = r instanceof JetSuperExpression; + final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface, isSuper); if (!isStatic) { if (receiver == StackValue.none()) { receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); } JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, r); - receiver.put(receiverType != null ? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v); + receiver.put(receiverType != null && !isSuper? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v); if(receiverType != null) { ClassDescriptor propReceiverDescriptor = (ClassDescriptor) propertyDescriptor.getContainingDeclaration(); if(!CodegenUtil.isInterface(propReceiverDescriptor) && CodegenUtil.isInterface(receiverType.getConstructor().getDeclarationDescriptor())) { @@ -895,11 +913,11 @@ public class ExpressionCodegen extends JetVisitor { StackValue.onStack(typeMapper.mapType(functionDescriptor.getReturnType())).coerce(type, v); } - public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface) { + public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, boolean forceInterface, boolean isSuper) { DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; propertyDescriptor = propertyDescriptor.getOriginal(); - boolean isInsideClass = !forceInterface && containingDeclaration == context.getContextClass(); + boolean isInsideClass = !forceInterface && containingDeclaration == context.getContextClass() && contextKind() != OwnerKind.TRAIT_IMPL; Method getter; Method setter; if (forceField) { @@ -909,10 +927,10 @@ public class ExpressionCodegen extends JetVisitor { else { //noinspection ConstantConditions getter = isInsideClass && (propertyDescriptor.getGetter() == null || propertyDescriptor.getGetter().isDefault()) - ? null : typeMapper.mapGetterSignature(propertyDescriptor); + ? null : typeMapper.mapGetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION); //noinspection ConstantConditions setter = isInsideClass && (propertyDescriptor.getSetter() == null || propertyDescriptor.getSetter().isDefault()) - ? null : typeMapper.mapSetterSignature(propertyDescriptor); + ? null : typeMapper.mapSetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION); } String owner; @@ -931,7 +949,7 @@ public class ExpressionCodegen extends JetVisitor { } } - return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(propertyDescriptor.getOutType()), isStatic, isInterface, getter, setter); + return StackValue.property(propertyDescriptor.getName(), owner, typeMapper.mapType(propertyDescriptor.getOutType()), isStatic, isInterface, isSuper, getter, setter); } @Override @@ -1009,10 +1027,10 @@ public class ExpressionCodegen extends JetVisitor { private DeclarationDescriptor resolveCalleeDescriptor(JetCallExpression call) { JetExpression callee = call.getCalleeExpression(); - if (!(callee instanceof JetSimpleNameExpression)) { + if (!(callee instanceof JetReferenceExpression)) { throw new UnsupportedOperationException("Don't know how to generate a call to " + callee); } - DeclarationDescriptor funDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) callee); + DeclarationDescriptor funDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) callee); if (funDescriptor == null) { throw new CompilationException("Cannot resolve: " + callee.getText()); } @@ -1883,7 +1901,7 @@ public class ExpressionCodegen extends JetVisitor { Type type = JetTypeMapper.psiClassType(javaClass); v.anew(type); v.dup(); - final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructor); + final CallableMethod callableMethod = JetTypeMapper.mapToCallableMethod(constructor); invokeMethodWithArguments(callableMethod, expression, StackValue.none()); return type; } @@ -2071,6 +2089,7 @@ public class ExpressionCodegen extends JetVisitor { return generateThisOrOuter((ClassDescriptor) descriptor); } else { + // estension function or ??? return thisExpression(); } } @@ -2481,7 +2500,7 @@ public class ExpressionCodegen extends JetVisitor { final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) call); if (descriptor instanceof PropertyDescriptor) { v.load(subjectLocal, subjectType); - conditionValue = intermediateValueForProperty((PropertyDescriptor) descriptor, false, false); + conditionValue = intermediateValueForProperty((PropertyDescriptor) descriptor, false, false, false); } else { throw new UnsupportedOperationException("unknown simple name resolve result: " + descriptor); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 6834d94c79c..609555fd4df 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -95,7 +95,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { v.defineClass(Opcodes.V1_6, Opcodes.ACC_PUBLIC | (isAbstract ? Opcodes.ACC_ABSTRACT : 0) | (isInterface ? Opcodes.ACC_INTERFACE - : 0), + : 0/*Opcodes.ACC_SUPER*/), jvmName(), null, superClass, @@ -652,7 +652,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if(propertyDescriptor.getOutType().isNullable()) type = JetTypeMapper.boxType(type); codegen.gen(initializer, type); - codegen.intermediateValueForProperty(propertyDescriptor, false, false).store(iv); + codegen.intermediateValueForProperty(propertyDescriptor, false, false, false).store(iv); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index ad1521696de..93646bbb4a0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -627,18 +627,29 @@ public class JetTypeMapper { answer.append(p.getName()); // TODO: BOUND! } - public Method mapGetterSignature(PropertyDescriptor descriptor) { + public Method mapGetterSignature(PropertyDescriptor descriptor, OwnerKind kind) { Type returnType = mapType(descriptor.getOutType()); - return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]); + if(kind != OwnerKind.TRAIT_IMPL) + return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]); + else { + ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration(); + return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[] { mapType(containingDeclaration.getDefaultType()) }); + } } - public Method mapSetterSignature(PropertyDescriptor descriptor) { + public Method mapSetterSignature(PropertyDescriptor descriptor, OwnerKind kind) { final JetType inType = descriptor.getInType(); if (inType == null) { return null; } Type paramType = mapType(inType); - return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType }); + if(kind != OwnerKind.TRAIT_IMPL) { + return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType }); + } + else { + ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration(); + return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { mapType(containingDeclaration.getDefaultType()), paramType }); + } } private Method mapConstructorSignature(ConstructorDescriptor descriptor, List valueParameterTypes) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index a456c64b74a..2bef71dfaa6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -32,7 +32,7 @@ public class NamespaceCodegen { this.state = state; v.defineClass(V1_6, - ACC_PUBLIC, + ACC_PUBLIC/*|ACC_SUPER*/, getJVMClassName(fqName), null, //"jet/lang/Namespace", @@ -93,7 +93,7 @@ public class NamespaceCodegen { if (initializer != null && !(initializer instanceof JetConstantExpression)) { final PropertyDescriptor descriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, declaration); codegen.genToJVMStack(initializer); - codegen.intermediateValueForProperty(descriptor, true, false).store(new InstructionAdapter(mv)); + codegen.intermediateValueForProperty(descriptor, true, false, false).store(new InstructionAdapter(mv)); } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index be9733fac27..ddb3f9ed8fd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -37,8 +37,9 @@ public class PropertyCodegen { throw new UnsupportedOperationException("expect a property to have a property descriptor"); } final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION) { - generateBackingField(p, propertyDescriptor); + if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind ==OwnerKind.TRAIT_IMPL ) { + if(kind != OwnerKind.TRAIT_IMPL) + generateBackingField(p, propertyDescriptor); generateGetter(p, propertyDescriptor); generateSetter(p, propertyDescriptor); } @@ -81,7 +82,7 @@ public class PropertyCodegen { final JetPropertyAccessor getter = p.getGetter(); if (getter != null) { if (getter.getBodyExpression() != null) { - functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor), propertyDescriptor.getGetter()); + functionCodegen.generateMethod(getter, state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind), propertyDescriptor.getGetter()); } else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { generateDefaultGetter(p, getter); @@ -102,7 +103,7 @@ public class PropertyCodegen { if (setter.getBodyExpression() != null) { final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); assert setterDescriptor != null; - functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor), setterDescriptor); + functionCodegen.generateMethod(setter, state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind), setterDescriptor); } else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { generateDefaultSetter(p, setter); @@ -120,6 +121,10 @@ public class PropertyCodegen { } public void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) { + if (kind == OwnerKind.TRAIT_IMPL) { + return; + } + if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } @@ -129,7 +134,7 @@ public class PropertyCodegen { if(isTrait && !(kind instanceof OwnerKind.DelegateKind)) flags |= Opcodes.ACC_ABSTRACT; - final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(); + final String signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind).getDescriptor(); String getterName = getterName(propertyDescriptor.getName()); MethodVisitor mv = v.newMethod(origin, flags, getterName, signature, null, null); if (!isTrait || kind instanceof OwnerKind.DelegateKind) { @@ -162,6 +167,10 @@ public class PropertyCodegen { } public void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) { + if (kind == OwnerKind.TRAIT_IMPL) { + return; + } + if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } @@ -171,7 +180,7 @@ public class PropertyCodegen { if(isTrait && !(kind instanceof OwnerKind.DelegateKind)) flags |= Opcodes.ACC_ABSTRACT; - final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(); + final String signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind).getDescriptor(); MethodVisitor mv = v.newMethod(origin, flags, setterName(propertyDescriptor.getName()), signature, null, null); if (!isTrait || kind instanceof OwnerKind.DelegateKind) { mv.visitCode(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 7938e019941..88badb3e2b8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -96,8 +96,8 @@ public abstract class StackValue { return new InstanceField(type, owner, name); } - public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, Method getter, Method setter) { - return new Property(name, owner, getter, setter, isStatic, isInterface, type); + public static StackValue property(String name, String owner, Type type, boolean isStatic, boolean isInterface, boolean isSuper, Method getter, Method setter) { + return new Property(name, owner, getter, setter, isStatic, isInterface, isSuper, type); } public static StackValue expression(Type type, JetExpression expression, ExpressionCodegen generator) { @@ -623,8 +623,9 @@ public abstract class StackValue { private final String owner; private final boolean isStatic; private final boolean isInterface; + private boolean isSuper; - public Property(String name, String owner, Method getter, Method setter, boolean aStatic, boolean isInterface, Type type) { + public Property(String name, String owner, Method getter, Method setter, boolean aStatic, boolean isInterface, boolean isSuper, Type type) { super(type); this.name = name; this.owner = owner; @@ -632,26 +633,37 @@ public abstract class StackValue { this.setter = setter; isStatic = aStatic; this.isInterface = isInterface; + this.isSuper = isSuper; } @Override public void put(Type type, InstructionAdapter v) { - if (getter == null) { - v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor()); + if(isSuper && isInterface) { + v.visitMethodInsn(Opcodes.INVOKESTATIC, owner + "$$TImpl", getter.getName(), getter.getDescriptor().replace("(","(L" + owner + ";")); } else { - v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor()); + if (getter == null) { + v.visitFieldInsn(isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD, owner, name, this.type.getDescriptor()); + } + else { + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isSuper ? Opcodes.INVOKESPECIAL : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, getter.getName(), getter.getDescriptor()); + } } coerce(type, v); } @Override public void store(InstructionAdapter v) { - if (setter == null) { - v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor()); + if(isSuper && isInterface) { + v.visitMethodInsn(Opcodes.INVOKESTATIC, owner + "$$TImpl", setter.getName(), setter.getDescriptor().replace("(","(L" + owner + ";")); } else { - v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor()); + if (setter == null) { + v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor()); + } + else { + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isSuper ? Opcodes.INVOKESPECIAL : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, setter.getName(), setter.getDescriptor()); + } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 1f084b731dc..6856689b2de 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -46,7 +46,7 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen { @Override protected void generateDeclaration() { v.defineClass(Opcodes.V1_6, - Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, + Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL/*| Opcodes.ACC_SUPER*/, jvmName(), null, "java/lang/Object", diff --git a/compiler/testData/codegen/super/basicproperty.jet b/compiler/testData/codegen/super/basicproperty.jet new file mode 100644 index 00000000000..196ed3f40b0 --- /dev/null +++ b/compiler/testData/codegen/super/basicproperty.jet @@ -0,0 +1,22 @@ +open class M() { + open var b: Int = 0 +} + +class N() : M() { + val a : Int + get() { + super.b = super.b + 1 + return super.b + 1 + } + override var b: Int = a + 1 + + val superb : Int + get() = super.b +} + +fun box(): String { + val n = N() + System.out?.println("a: " + n.a + " b: " + n.b + " superb: " + n.superb) + if (n.b == 3 && n.a == 4 && n.superb == 3) return "OK"; + return "fail"; +} \ No newline at end of file diff --git a/compiler/testData/codegen/super/traitproperty.jet b/compiler/testData/codegen/super/traitproperty.jet new file mode 100644 index 00000000000..962f71c5dc9 --- /dev/null +++ b/compiler/testData/codegen/super/traitproperty.jet @@ -0,0 +1,29 @@ +trait M { + var backingB : Int + var b : Int + get() = backingB + set(value: Int) { + backingB = value + } +} + +class N() : M { + override var backingB : Int = 0 + + val a : Int + get() { + super.b = super.b + 1 + return super.b + 1 + } + override var b: Int = a + 1 + + val superb : Int + get() = super.b +} + +fun box(): String { + val n = N() + System.out?.println("a: " + n.a + " b: " + n.b + " superb: " + n.superb) + if (n.b == 3 && n.a == 4 && n.superb == 3) return "OK"; + return "fail"; +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 1bbef086700..0a3a3950b4c 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -80,4 +80,55 @@ public class FunctionGenTest extends CodegenTestCase { public void testKt395 () { blackBoxFile("regressions/kt395.jet"); } +/* + public void testFunction () throws InvocationTargetException, IllegalAccessException { + loadText("fun Any.foo() : fun(): String {\n" + + " return { \"239\" + this }\n" + + "}\n" + + "fun box() : String {\n" + + " return if((10.foo())() == \"23910\") \"OK\" else \"fail\"" + + "}" + + ""); + System.out.println(generateToText()); + Method foo = generateFunction(); + assertTrue((Boolean) foo.invoke(null, "lala")); + assertFalse((Boolean) foo.invoke(null, "mama")); + } + +fun Any.foo() : fun() : Unit { + return {} +} + +fun Any.foo1() : fun(i : Int) : Unit { + return {} +} + +fun foo2() : fun(i : fun()) : Unit { + return {} +} + +fun fooT1(t : T) : fun() : T { + return {t} +} + +fun fooT2() : fun(t : T) : T { + return {it} +} + +fun main(args : Array) { + args.foo()() + + args.foo1()(1) + + foo2()({}) + (foo2()){} + + val a = fooT1(1)() + a : Int + + val b = fooT2()(1) + b : Int + fooT2()(1) // : Any? +} + */ } diff --git a/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java new file mode 100644 index 00000000000..66600588972 --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java @@ -0,0 +1,13 @@ +package org.jetbrains.jet.codegen; + +public class SuperGenTest extends CodegenTestCase { + public void testBasicProperty () { + blackBoxFile("/super/basicproperty.jet"); + System.out.println(generateToText()); + } + + public void testTraitProperty () { + blackBoxFile("/super/traitproperty.jet"); + System.out.println(generateToText()); + } +} From 98774400ce2319e1552ecf0539276b6252dc074b Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 4 Nov 2011 14:23:26 +0100 Subject: [PATCH 15/16] initial super.method() --- .../jetbrains/jet/codegen/CodegenUtil.java | 40 ----------------- .../jet/codegen/ExpressionCodegen.java | 7 +-- .../codegen/ImplementationBodyCodegen.java | 6 +-- .../jetbrains/jet/codegen/JetTypeMapper.java | 44 +++++++++++++++++-- .../testData/codegen/super/basicmethod.jet | 13 ++++++ .../jetbrains/jet/codegen/SuperGenTest.java | 5 +++ 6 files changed, 65 insertions(+), 50 deletions(-) create mode 100644 compiler/testData/codegen/super/basicmethod.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 3e3fe413c90..01c767cfd25 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -1,14 +1,9 @@ package org.jetbrains.jet.codegen; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.lang.types.TypeProjection; import org.objectweb.asm.Type; /** @@ -67,39 +62,4 @@ public class CodegenUtil { return hasOuterTypeInfo(outerClassDescriptor); } - - public static boolean hasTypeInfoField(JetType type) { - if(type.getConstructor().getParameters().size() > 0) - return true; - - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(hasTypeInfoField(jetType)) - return true; - } - - ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor()); - if(outerClassDescriptor == null) - return false; - - return hasTypeInfoField(outerClassDescriptor.getDefaultType()); - } - - public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) { - if(!exceptOwn) { - if(!isInterface(type)) - if(hasTypeInfoField(type)) - return true; - } - - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(hasDerivedTypeInfoField(jetType, false)) - return true; - } - - return false; - } - - public static Type arrayElementType(Type type) { - return Type.getType(type.getDescriptor().substring(1)); - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index ec5777f8558..1792a90c644 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2279,7 +2279,8 @@ public class ExpressionCodegen extends JetVisitor { private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) { DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); - if (jetType.getArguments().size() > 0 || !(descriptor instanceof ClassDescriptor)) { + boolean javaClass = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor) instanceof PsiClass; + if (!javaClass && (jetType.getArguments().size() > 0 || !(descriptor instanceof ClassDescriptor))) { generateTypeInfo(jetType); expressionToGen.put(OBJECT_TYPE, v); if (leaveExpressionOnStack) { @@ -2325,7 +2326,7 @@ public class ExpressionCodegen extends JetVisitor { return; } - if(!CodegenUtil.hasTypeInfoField(jetType)) { + if(!typeMapper.hasTypeInfoField(jetType) && !(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetType.getConstructor().getDeclarationDescriptor()) instanceof PsiClass)) { // TODO: we need some better checks here v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); return; @@ -2387,7 +2388,7 @@ public class ExpressionCodegen extends JetVisitor { ownerType = JetTypeMapper.boxType(ownerType); if (containingDeclaration == context.getContextClass()) { if(!CodegenUtil.isInterface(descriptor)) { - if (CodegenUtil.hasTypeInfoField(defaultType)) { + if (typeMapper.hasTypeInfoField(defaultType)) { v.load(0, JetTypeMapper.TYPE_OBJECT); v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 609555fd4df..98838271061 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -339,7 +339,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.putfield(classname, fieldName, interfaceDesc); } - if (CodegenUtil.hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { + if (state.getTypeMapper().hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv); } @@ -706,8 +706,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; JetType defaultType = descriptor.getDefaultType(); - if(CodegenUtil.hasTypeInfoField(defaultType)) { - if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) { + if(state.getTypeMapper().hasTypeInfoField(defaultType)) { + if(!state.getTypeMapper().hasDerivedTypeInfoField(defaultType, true)) { v.newField(myClass, Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 93646bbb4a0..66737f8de1e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -186,6 +186,39 @@ public class JetTypeMapper { return type; } + public boolean hasTypeInfoField(JetType type) { + if(type.getConstructor().getParameters().size() > 0) { + if(!(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getConstructor().getDeclarationDescriptor()) instanceof PsiClass)) + return true; + } + + for (JetType jetType : type.getConstructor().getSupertypes()) { + if(hasTypeInfoField(jetType)) + return true; + } + + ClassDescriptor outerClassDescriptor = CodegenUtil.getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor()); + if(outerClassDescriptor == null) + return false; + + return hasTypeInfoField(outerClassDescriptor.getDefaultType()); + } + + public boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) { + if(!exceptOwn) { + if(!CodegenUtil.isInterface(type)) + if(hasTypeInfoField(type)) + return true; + } + + for (JetType jetType : type.getConstructor().getSupertypes()) { + if(hasDerivedTypeInfoField(jetType, false)) + return true; + } + + return false; + } + public String jvmName(ClassDescriptor jetClass, OwnerKind kind) { PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass); if (declaration instanceof PsiClass) { @@ -665,9 +698,12 @@ public class JetTypeMapper { valueParameterTypes.add(type); } - List typeParameters = classDescriptor.getTypeConstructor().getParameters(); - for (int n = typeParameters.size(); n > 0; n--) { - parameterTypes.add(TYPE_TYPEINFO); + PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor); + if(!(psiElement instanceof PsiClass)) { + List typeParameters = classDescriptor.getTypeConstructor().getParameters(); + for (int n = typeParameters.size(); n > 0; n--) { + parameterTypes.add(TYPE_TYPEINFO); + } } return new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); @@ -678,7 +714,7 @@ public class JetTypeMapper { final Method method = mapConstructorSignature(descriptor, valueParameterTypes); String owner = jvmName(descriptor.getContainingDeclaration(), kind); final CallableMethod result = new CallableMethod(owner, method, Opcodes.INVOKESPECIAL, valueParameterTypes); - result.setAcceptsTypeArguments(true); + result.setAcceptsTypeArguments(!(bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor.getContainingDeclaration()) instanceof PsiClass)); return result; } diff --git a/compiler/testData/codegen/super/basicmethod.jet b/compiler/testData/codegen/super/basicmethod.jet new file mode 100644 index 00000000000..ab735673036 --- /dev/null +++ b/compiler/testData/codegen/super/basicmethod.jet @@ -0,0 +1,13 @@ +class N() : java.util.ArrayList() { + override fun add(el: String) : Boolean { + super.add(el) + return super.add(el + el) + } +} + +fun box(): String { + val n = N() + n.add("239") + if (n.get(0) == "239" && n.get(1) == "239239") return "OK"; + return "fail"; +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java index 66600588972..45bf1a6c19b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/SuperGenTest.java @@ -10,4 +10,9 @@ public class SuperGenTest extends CodegenTestCase { blackBoxFile("/super/traitproperty.jet"); System.out.println(generateToText()); } + + public void testBasicMethod () { + blackBoxFile("/super/basicmethod.jet"); + System.out.println(generateToText()); + } } From 498797b0137469a4698df74b11034a4a50755d55 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Fri, 4 Nov 2011 06:05:34 +0300 Subject: [PATCH 16/16] Plugable asm visitors strategy --- .idea/libraries/asm.xml | 4 +- .../jet/codegen/ClassBuilderFactory.java | 57 +++++++++++++++++++ .../jet/codegen/ClassFileFactory.java | 40 ++----------- .../jet/codegen/GenerationState.java | 4 +- .../jet/compiler/CompileSession.java | 3 +- .../jet/codegen/CodegenTestCase.java | 4 +- .../jet/plugin/compiler/JetCompiler.java | 3 +- 7 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactory.java diff --git a/.idea/libraries/asm.xml b/.idea/libraries/asm.xml index 479c49dcb20..fc8083b4e42 100644 --- a/.idea/libraries/asm.xml +++ b/.idea/libraries/asm.xml @@ -4,6 +4,8 @@ - + + + \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactory.java new file mode 100644 index 00000000000..dc4075d0cf4 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactory.java @@ -0,0 +1,57 @@ +package org.jetbrains.jet.codegen; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * @author max + */ +public interface ClassBuilderFactory { + ClassBuilder newClassBuilder(); + String asText(ClassBuilder builder); + byte[] asBytes(ClassBuilder builder); + + ClassBuilderFactory TEXT = new ClassBuilderFactory() { + @Override + public ClassBuilder newClassBuilder() { + return new ClassBuilder(new TraceClassVisitor(new PrintWriter(new StringWriter()))); + } + + @Override + public String asText(ClassBuilder builder) { + TraceClassVisitor visitor = (TraceClassVisitor) builder.getVisitor(); + + StringWriter writer = new StringWriter(); + visitor.print(new PrintWriter(writer)); + + return writer.toString(); + } + + @Override + public byte[] asBytes(ClassBuilder builder) { + throw new UnsupportedOperationException("TEXT generator asked for bytes"); + } + }; + + ClassBuilderFactory BINARIES = new ClassBuilderFactory() { + @Override + public ClassBuilder newClassBuilder() { + return new ClassBuilder(new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); + } + + @Override + public String asText(ClassBuilder builder) { + throw new UnsupportedOperationException("BINARIES generator asked for text"); + } + + @Override + public byte[] asBytes(ClassBuilder builder) { + ClassWriter visitor = (ClassWriter) builder.getVisitor(); + return visitor.toByteArray(); + } + }; + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index 0fadb452d83..98da6b5fb40 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -1,42 +1,26 @@ package org.jetbrains.jet.codegen; -import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.psi.JetNamespace; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.util.TraceClassVisitor; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.*; /** * @author max */ public class ClassFileFactory { - private final Project project; - private final boolean isText; + private final ClassBuilderFactory builderFactory; private final Map ns2codegen = new HashMap(); private final Map generators = new LinkedHashMap(); private boolean isDone = false; public final GenerationState state; - public ClassFileFactory(Project project, boolean text, GenerationState state) { - this.project = project; - isText = text; + public ClassFileFactory(ClassBuilderFactory builderFactory, GenerationState state) { + this.builderFactory = builderFactory; this.state = state; } ClassBuilder newVisitor(String filePath) { - ClassVisitor visitor; - if (isText) { - visitor = new TraceClassVisitor(new PrintWriter(new StringWriter())); - } - else { - visitor = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - } - - final ClassBuilder answer = new ClassBuilder(visitor); + final ClassBuilder answer = builderFactory.newClassBuilder(); generators.put(filePath, answer); return answer; } @@ -68,25 +52,13 @@ public class ClassFileFactory { } public String asText(String file) { - assert isText : "Need to create with text=true"; - done(); - - TraceClassVisitor visitor = (TraceClassVisitor) generators.get(file).getVisitor(); - - StringWriter writer = new StringWriter(); - visitor.print(new PrintWriter(writer)); - - return writer.toString(); + return builderFactory.asText(generators.get(file)); } public byte[] asBytes(String file) { - assert !isText : "This is debug stuff, only produces texts."; - done(); - - ClassWriter visitor = (ClassWriter) generators.get(file).getVisitor(); - return visitor.toByteArray(); + return builderFactory.asBytes(generators.get(file)); } public List files() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 8a4ec90771a..5c50f0bcf7b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -28,10 +28,10 @@ public class GenerationState { private final JetStandardLibrary standardLibrary; private final IntrinsicMethods intrinsics; - public GenerationState(Project project, boolean text) { + public GenerationState(Project project, ClassBuilderFactory builderFactory) { this.project = project; this.standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); - this.factory = new ClassFileFactory(project, text, this); + this.factory = new ClassFileFactory(builderFactory, this); this.intrinsics = new IntrinsicMethods(project, standardLibrary); } diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java index c166906ed87..7f643b90d14 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java @@ -5,6 +5,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import org.jetbrains.jet.JetCoreEnvironment; +import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; @@ -93,7 +94,7 @@ public class CompileSession { } public ClassFileFactory generate() { - GenerationState generationState = new GenerationState(myEnvironment.getProject(), false); + GenerationState generationState = new GenerationState(myEnvironment.getProject(), ClassBuilderFactory.BINARIES); generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces); return generationState.getFactory(); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index e6ec1009270..4bff106d65b 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -98,7 +98,7 @@ public abstract class CodegenTestCase extends JetLiteFixture { } protected String generateToText() { - GenerationState state = new GenerationState(getProject(), true); + GenerationState state = new GenerationState(getProject(), ClassBuilderFactory.TEXT); AnalyzingUtils.checkForSyntacticErrors(myFile); state.compile(myFile); @@ -152,7 +152,7 @@ public abstract class CodegenTestCase extends JetLiteFixture { protected ClassFileFactory generateClassesInFile() { try { - GenerationState state = new GenerationState(getProject(), false); + GenerationState state = new GenerationState(getProject(), ClassBuilderFactory.BINARIES); AnalyzingUtils.checkForSyntacticErrors(myFile); state.compile(myFile); diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index 7327491ec3c..162d97555e2 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -16,6 +16,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.util.Chunk; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; @@ -69,7 +70,7 @@ public class JetCompiler implements TranslatingCompiler { public void run() { VirtualFile[] allFiles = compileContext.getCompileScope().getFiles(null, true); - GenerationState generationState = new GenerationState(compileContext.getProject(), false); + GenerationState generationState = new GenerationState(compileContext.getProject(), ClassBuilderFactory.BINARIES); List namespaces = Lists.newArrayList(); for (VirtualFile virtualFile : allFiles) { PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile);