From 301f8bdd7b8c34c8ef3655b090a9270619c8fceb Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 24 Oct 2011 20:55:10 +0400 Subject: [PATCH 01/31] Test added for non-* imports --- .../quick/ImportResolutionOrder.jet | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/testData/checkerWithErrorTypes/quick/ImportResolutionOrder.jet b/compiler/testData/checkerWithErrorTypes/quick/ImportResolutionOrder.jet index 1b12d676fe7..acaeadc053c 100644 --- a/compiler/testData/checkerWithErrorTypes/quick/ImportResolutionOrder.jet +++ b/compiler/testData/checkerWithErrorTypes/quick/ImportResolutionOrder.jet @@ -10,3 +10,14 @@ namespace b { } } + +namespace c { + import d.X + val x : X = X() +} + +namespace d { + class X() { + + } +} From 62af2437a9c16e72b0baafe4eef6818374091e08 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 24 Oct 2011 21:29:29 +0400 Subject: [PATCH 02/31] Better errors reporting for this case: namespace a { import // <-- error } // <-- reported here namespace b { class Y { class object {} class Z {} } } // <-- used to be reported here --- .../frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 9ab713325aa..57471dc7120 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -167,7 +167,7 @@ public class JetParsing extends AbstractJetParsing { } PsiBuilder.Marker reference = mark(); - expect(IDENTIFIER, "Expecting qualified name", TokenSet.create(DOT, AS_KEYWORD)); + expect(IDENTIFIER, "Expecting qualified name"); reference.done(REFERENCE_EXPRESSION); while (at(DOT) && lookahead(1) != MUL) { advance(); // DOT From 37c9e00c3fc0109507d366a23f09d80c8168900f Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 27 Oct 2011 20:16:22 +0400 Subject: [PATCH 03/31] Test for : KT-282 Nullability in extension functions and in binary calls --- .../quick/regressions/kt282.jet | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt282.jet diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt282.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt282.jet new file mode 100644 index 00000000000..bd6d55ce380 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt282.jet @@ -0,0 +1,18 @@ +// KT-282 Nullability in extension functions and in binary calls + +class Set { + fun contains(x : Int) : Boolean = true +} + +fun Set?.plus(x : Int) : Int = 1 + +fun Int?.contains(x : Int) : Boolean = false + +fun f(): Unit { + var set : Set? = null + val i : Int? = null + i + 1 + set + 1 + 1 in set + 1 in 2 +} \ No newline at end of file From cff5ea58de32f1f9c60b73d2030952437ee40efe Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 27 Oct 2011 21:27:57 +0400 Subject: [PATCH 04/31] KT-128 Support passing only the last closure if all the other parameters have default values --- .../quick/regressions/kt128.jet | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt128.jet diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt128.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt128.jet new file mode 100644 index 00000000000..efc005cf183 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt128.jet @@ -0,0 +1,12 @@ +// KT-128 Support passing only the last closure if all the other parameters have default values + +fun div(c : String = "", f : fun()) {} +fun f() { + div { // Nothing passed, but could have been... + // ... + } + + div (c = "foo") { // More things could have been passed + // ... + } +} \ No newline at end of file From b467dc2de1659681aec91a9e7f6aac0d8a595945 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 27 Oct 2011 21:29:44 +0400 Subject: [PATCH 05/31] KT-127 Support extension functions in when expressions --- .../quick/regressions/kt127.jet | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt127.jet diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt127.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt127.jet new file mode 100644 index 00000000000..7bcb076f08c --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt127.jet @@ -0,0 +1,15 @@ +// KT-127 Support extension functions in when expressions + +class Foo() {} + +fun Any.equals(other : Any?) : Boolean = true +fun Any?.equals1(other : Any?) : Boolean = true + +fun main(args: Array) { + + val command : Foo? = null + when (command) { + .equals(null) => 1; // must be resolved + ?.equals(null) => 1 // same here + } +} From e55b4491aea2ef1da61ed8cdc23c3f7b3a9d26b3 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 18:07:18 +0400 Subject: [PATCH 06/31] Test for KT-26 Import namespaces defined in this file --- .../checkerWithErrorTypes/quick/regressions/kt26-1.jet | 7 +++++++ .../checkerWithErrorTypes/quick/regressions/kt26.jet | 10 ++++++++++ compiler/testData/psi/Imports_ERR.txt | 10 +++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt26-1.jet create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt26.jet diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26-1.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26-1.jet new file mode 100644 index 00000000000..ff27f3515f3 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26-1.jet @@ -0,0 +1,7 @@ +// KT-26 Import namespaces defined in this file + +namespace foo { + import bar.* // Must not be an error +} + +namespace bar {} \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26.jet new file mode 100644 index 00000000000..f79b7a901f8 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt26.jet @@ -0,0 +1,10 @@ +// KT-26 Import namespaces defined in this file + +import html.* // Must not be an error + +namespace html { + + abstract class Factory { + fun create() : T? = null + } +} \ No newline at end of file diff --git a/compiler/testData/psi/Imports_ERR.txt b/compiler/testData/psi/Imports_ERR.txt index f9832e87923..5ad833b88df 100644 --- a/compiler/testData/psi/Imports_ERR.txt +++ b/compiler/testData/psi/Imports_ERR.txt @@ -18,7 +18,8 @@ JetFile: Imports_ERR.jet PsiWhiteSpace(' ') REFERENCE_EXPRESSION PsiErrorElement:Expecting qualified name - PsiElement(SEMICOLON)(';') + + PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n') IMPORT_DIRECTIVE PsiElement(import)('import') @@ -27,7 +28,9 @@ JetFile: Imports_ERR.jet PsiElement(DOT)('.') REFERENCE_EXPRESSION PsiErrorElement:Expecting qualified name - PsiElement(MUL)('*') + + PsiErrorElement:Expecting namespace or top level declaration + PsiElement(MUL)('*') PsiWhiteSpace('\n') IMPORT_DIRECTIVE PsiElement(import)('import') @@ -37,7 +40,8 @@ JetFile: Imports_ERR.jet PsiWhiteSpace(' ') REFERENCE_EXPRESSION PsiErrorElement:Expecting qualified name - PsiElement(SEMICOLON)(';') + + PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n\n') IMPORT_DIRECTIVE PsiElement(import)('import') From 846aa6f3a17dda2cf9cb01577c9d9ab6b996e3dd Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Fri, 28 Oct 2011 16:33:43 +0200 Subject: [PATCH 07/31] private constructor added --- .../org/jetbrains/jet/lang/resolve/BindingContextUtils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index 17ea97a2e83..3e5a057b0e0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -8,6 +8,9 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression; * @author abreslav */ public class BindingContextUtils { + private BindingContextUtils() { + } + public static PsiElement resolveToDeclarationPsiElement(BindingContext bindingContext, JetReferenceExpression referenceExpression) { DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression); if (declarationDescriptor == null) { From 65ded5b9772855c4ef492eac81d235c1c466136c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 28 Oct 2011 16:36:05 +0200 Subject: [PATCH 08/31] KotlinCompiler can build a jar file --- .../org/jetbrains/jet/cli/KotlinCompiler.java | 129 ++++++++++++++++-- .../jetbrains/jet/plugin/JetMainDetector.java | 35 +++++ .../run/JetRunConfigurationProducer.java | 26 +--- 3 files changed, 153 insertions(+), 37 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/plugin/JetMainDetector.java diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 68f4809ee36..1f60ab2269b 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -10,6 +10,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.util.Processor; import com.sampullara.cli.Args; import com.sampullara.cli.Argument; import org.jetbrains.jet.JetCoreEnvironment; @@ -25,22 +26,29 @@ import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; +import org.jetbrains.jet.plugin.JetMainDetector; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; import java.util.List; +import java.util.jar.*; /** * @author yole * @author alex.tkachman */ +@SuppressWarnings("UseOfSystemOutOrSystemErr") public class KotlinCompiler { public static class Arguments { @Argument(value = "output", description = "output directory") public String outputDir; + @Argument(value = "jar", description = "jar file name") + public String jar; @Argument(value = "src", description = "source file or directory", required = true) public String src; } @@ -52,7 +60,7 @@ public class KotlinCompiler { Args.parse(arguments, args); } catch (Throwable t) { - System.out.println("Usage: KotlinCompiler -output -src "); + System.out.println("Usage: KotlinCompiler [-output |-jar ] -src "); t.printStackTrace(); return; } @@ -78,6 +86,7 @@ public class KotlinCompiler { Project project = environment.getProject(); GenerationState generationState = new GenerationState(project, false); List namespaces = Lists.newArrayList(); + String mainClass = null; if(vFile.isDirectory()) { File dir = new File(vFile.getPath()); addFiles(environment, project, namespaces, dir); @@ -85,7 +94,11 @@ public class KotlinCompiler { else { PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile); if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); + final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace(); + if (JetMainDetector.hasMain(namespace.getDeclarations())) { + mainClass = namespace.getFQName() + ".namespace"; + } + namespaces.add(namespace); } else { System.out.print("Not a Kotlin file: " + vFile.getPath()); @@ -102,25 +115,113 @@ public class KotlinCompiler { generationState.compileCorrectNamespaces(bindingContext, namespaces); final ClassFileFactory factory = generationState.getFactory(); - if(arguments.outputDir == null) { - System.out.println("Output directory is not specified - no files will be saved to the disk"); + if (arguments.jar != null) { + writeToJar(factory, arguments.jar, mainClass, true); + } + else if (arguments.outputDir != null) { + writeToOutputDirectory(factory, arguments.outputDir); } else { - List files = factory.files(); - for (String file : files) { - File target = new File(arguments.outputDir, file); - try { - FileUtil.writeToFile(target, factory.asBytes(file)); - System.out.println("Generated classfile: " + target); - } catch (IOException e) { - System.out.println(e.getMessage()); - } - } + System.out.println("Output directory or jar file is not specified - no files will be saved to the disk"); } } } + private static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) { + try { + Manifest manifest = new Manifest(); + final Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.putValue("Manifest-Version", "1.0"); + mainAttributes.putValue("Created-By", "JetBrains Kotlin"); + 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()) { + stream.putNextEntry(new JarEntry(file)); + stream.write(factory.asBytes(file)); + } + if (includeRuntime) { + writeRuntimeToJar(stream); + } + } + finally { + stream.close(); + fos.close(); + } + + } catch (IOException e) { + System.out.println("Failed to generate jar file: " + e.getMessage()); + } + } + + private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException { + URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); + if (url == null) { + System.out.println("Couldn't find runtime library"); + return; + } + final String protocol = url.getProtocol(); + final String path = url.getPath(); + if (protocol.equals("file")) { // unpacked runtime + final File stdlibDir = new File(path).getParentFile().getParentFile(); + FileUtil.processFilesRecursively(stdlibDir, new Processor() { + @Override + public boolean process(File file) { + if (file.isDirectory()) return true; + final String relativePath = FileUtil.getRelativePath(stdlibDir, file); + try { + stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath))); + FileInputStream fis = new FileInputStream(file); + try { + FileUtil.copy(fis, stream); + } finally { + fis.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return true; + } + }); + } + else if (protocol.equals("jar")) { + File jar = new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); + JarInputStream jis = new JarInputStream(new FileInputStream(jar)); + try { + while (true) { + JarEntry e = jis.getNextJarEntry(); + if (e == null) { + break; + } + stream.putNextEntry(e); + FileUtil.copy(jis, stream); + } + } finally { + jis.close(); + } + } + else { + System.out.println("Couldn't copy runtime library from " + url + ", protocol " + protocol); + } + } + + private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { + List files = factory.files(); + for (String file : files) { + File target = new File(outputDir, file); + try { + FileUtil.writeToFile(target, factory.asBytes(file)); + System.out.println("Generated classfile: " + target); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + } + private static class ErrorCollector { Multimap maps = LinkedHashMultimap.create(); diff --git a/compiler/frontend/src/org/jetbrains/jet/plugin/JetMainDetector.java b/compiler/frontend/src/org/jetbrains/jet/plugin/JetMainDetector.java new file mode 100644 index 00000000000..ec98c2d8eff --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/plugin/JetMainDetector.java @@ -0,0 +1,35 @@ +package org.jetbrains.jet.plugin; + +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.jet.lang.psi.JetTypeReference; + +import java.util.List; + +/** + * @author yole + */ +public class JetMainDetector { + private JetMainDetector() { + } + + public static boolean hasMain(List declarations) { + for (JetDeclaration declaration : declarations) { + if (declaration instanceof JetNamedFunction) { + JetNamedFunction function = (JetNamedFunction) declaration; + if ("main".equals(function.getName())) { + List parameters = function.getValueParameters(); + if (parameters.size() == 1) { + JetTypeReference reference = parameters.get(0).getTypeReference(); + if (reference != null && reference.getText().equals("Array")) { // TODO correct check + return true; + } + } + } + + } + } + return false; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java index dd8011fb41e..439124e4b46 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java @@ -9,8 +9,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.jet.lang.psi.*; - -import java.util.List; +import org.jetbrains.jet.plugin.JetMainDetector; /** * @author yole @@ -30,14 +29,14 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im @Override protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext configurationContext) { JetClass containingClass = (JetClass) location.getParentElement(JetClass.class); - if (containingClass != null && hasMain(containingClass.getDeclarations())) { + if (containingClass != null && JetMainDetector.hasMain(containingClass.getDeclarations())) { mySourceElement = containingClass; return createConfigurationByQName(location.getModule(), configurationContext, containingClass.getFQName()); } PsiFile psiFile = location.getPsiElement().getContainingFile(); if (psiFile instanceof JetFile) { JetNamespace namespace = ((JetFile) psiFile).getRootNamespace(); - if (hasMain(namespace.getDeclarations())) { + if (JetMainDetector.hasMain(namespace.getDeclarations())) { mySourceElement = namespace; return createConfigurationByQName(location.getModule(), configurationContext, namespace.getFQName() + ".namespace"); } @@ -45,25 +44,6 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im return null; } - private boolean hasMain(List declarations) { - for (JetDeclaration declaration : declarations) { - if (declaration instanceof JetNamedFunction) { - JetNamedFunction function = (JetNamedFunction) declaration; - if ("main".equals(function.getName())) { - List parameters = function.getValueParameters(); - if (parameters.size() == 1) { - JetTypeReference reference = parameters.get(0).getTypeReference(); - if (reference != null && reference.getText().equals("Array")) { // TODO correct check - return true; - } - } - } - - } - } - return false; - } - private RunnerAndConfigurationSettings createConfigurationByQName(Module module, ConfigurationContext context, String fqName) { RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(module.getProject(), context); JetRunConfiguration configuration = (JetRunConfiguration) settings.getConfiguration(); From af1840e5c0bba8bc8131a5e75210b817ee1344e0 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 28 Oct 2011 17:15:57 +0200 Subject: [PATCH 09/31] attempt to write a module script --- examples/src/Hello.kts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/src/Hello.kts diff --git a/examples/src/Hello.kts b/examples/src/Hello.kts new file mode 100644 index 00000000000..936a1694ffc --- /dev/null +++ b/examples/src/Hello.kts @@ -0,0 +1,5 @@ +import kotlin.modules.ModuleSetBuilder + +fun defineModules(builder: ModuleSetBuilder) { + +} \ No newline at end of file From 51c1ce836ac14116b78e8022a00629e31074fe1d Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 21:53:42 +0400 Subject: [PATCH 10/31] KT-412 Import not resolved if namespace structure doesn't match directory structure --- idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java | 4 +++- stdlib/ktSrc/ModuleBuilder.kt | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index c29a35c2ea3..0b6854b3770 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -66,9 +66,11 @@ public class JetCompiler implements TranslatingCompiler { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { + VirtualFile[] allFiles = compileContext.getCompileScope().getFiles(null, true); + GenerationState generationState = new GenerationState(compileContext.getProject(), false); List namespaces = Lists.newArrayList(); - for (VirtualFile virtualFile : virtualFiles) { + for (VirtualFile virtualFile : allFiles) { PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile); if (psiFile instanceof JetFile) { namespaces.add(((JetFile) psiFile).getRootNamespace()); diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index f6e97a1cdf1..2f90dcb1158 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -1,4 +1,6 @@ -namespace kotlin.modules +namespace kotlin + +namespace modules { import java.util.* import jet.modules.* @@ -45,3 +47,5 @@ class ModuleBuilder(val name: String): IModuleBuilder { override fun getSourceFiles(): List? = sourceFiles override fun getClasspathRoots(): List? = classpathRoots } + +} \ No newline at end of file From 04d4b8d53ddcc0f2bd63d7679038d0d938c69f49 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 22:30:17 +0400 Subject: [PATCH 11/31] A stupid implementation of resolve for multiple files in the IDE --- .../jet/lang/resolve/AnalyzingUtils.java | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 007c0c8340a..9a4e22e6374 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -1,11 +1,13 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.collect.Lists; +import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiErrorElement; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; @@ -14,7 +16,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.diagnostics.*; +import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder; +import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; @@ -123,9 +128,24 @@ public class AnalyzingUtils { @Override public Result compute() { synchronized (lock) { + final Project project = file.getProject(); + final List namespaces = Lists.newArrayList(); + ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + VirtualFile[] contentRoots = rootManager.getContentRoots(); + + CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { + @Override + protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { + if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile instanceof JetFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + }); try { - JetNamespace rootNamespace = file.getRootNamespace(); - BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY); +// JetNamespace rootNamespace = file.getRootNamespace(); + BindingContext bindingContext = analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); } catch (ProcessCanceledException e) { From 9c49f551a97e462374a2434b6a6041bf2a0214f4 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 22:41:01 +0400 Subject: [PATCH 12/31] Tests fixed --- .../jet/lang/resolve/AnalyzingUtils.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 9a4e22e6374..70178295035 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; @@ -131,18 +132,23 @@ public class AnalyzingUtils { final Project project = file.getProject(); final List namespaces = Lists.newArrayList(); ProjectRootManager rootManager = ProjectRootManager.getInstance(project); - VirtualFile[] contentRoots = rootManager.getContentRoots(); + if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { + VirtualFile[] contentRoots = rootManager.getContentRoots(); - CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { - @Override - protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { - if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); + CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { + @Override + protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { + if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile instanceof JetFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } } - } - }); + }); + } + else { + namespaces.add(file.getRootNamespace()); + } try { // JetNamespace rootNamespace = file.getRootNamespace(); BindingContext bindingContext = analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); From d0b0d5f265a27e0097f86edc448ee42b4cb9979e Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 22:45:29 +0400 Subject: [PATCH 13/31] Fixed adding annotation to a wrong file --- idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index d2be0e6939d..6272bae35b2 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -60,6 +60,7 @@ public class JetPsiChecker implements Annotator { Collection diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); Set redeclarations = Sets.newHashSet(); for (Diagnostic diagnostic : diagnostics) { + if (diagnostic.getFactory().getPsiFile(diagnostic) != file) continue; Annotation annotation = null; if (diagnostic.getSeverity() == Severity.ERROR) { if (diagnostic instanceof UnresolvedReferenceDiagnostic) { From 473779befa862a04c4d85cf5cd8873626f65183b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 28 Oct 2011 23:11:14 +0400 Subject: [PATCH 14/31] Redeclarations now report the redeclared name --- .../jet/lang/diagnostics/RedeclarationDiagnostic.java | 6 +++--- .../lang/diagnostics/RedeclarationDiagnosticFactory.java | 4 ++-- .../jet/lang/resolve/TraceBasedRedeclarationHandler.java | 2 +- .../org/jetbrains/jet/plugin/annotations/JetPsiChecker.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java index 9092b9edf19..3a8c2f02733 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java @@ -15,8 +15,8 @@ import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR; public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement { public class SimpleRedeclarationDiagnostic extends DiagnosticWithPsiElementImpl implements RedeclarationDiagnostic { - public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement) { - super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration", psiElement); + public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement, @NotNull String name) { + super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration: " + name, psiElement); } } @@ -66,7 +66,7 @@ public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); Set redeclarations = Sets.newHashSet(); for (Diagnostic diagnostic : diagnostics) { - if (diagnostic.getFactory().getPsiFile(diagnostic) != file) continue; + if (diagnostic.getFactory().getPsiFile(diagnostic) != file) continue; // This is needed because we have the same context for all files Annotation annotation = null; if (diagnostic.getSeverity() == Severity.ERROR) { if (diagnostic instanceof UnresolvedReferenceDiagnostic) { From fc01eb2dcf000039b408f0fec92704a9b8ed41be Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 30 Oct 2011 12:03:10 +0300 Subject: [PATCH 15/31] Fixing dependencies & nested modules --- .../jet/lang/resolve/java/AnalyzerFacade.java | 78 ++++++++++++++++++- .../jet/lang/resolve/AnalyzingUtils.java | 76 ++---------------- .../jet/lang/resolve/TopDownAnalyzer.java | 11 ++- .../lang/resolve/TypeHierarchyResolver.java | 2 +- .../jet/checkers/CheckerTestUtilTest.java | 3 +- .../jet/checkers/QuickJetPsiCheckerTest.java | 3 +- 6 files changed, 92 insertions(+), 81 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java index e0772dbcd28..867cf723b8a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java @@ -1,23 +1,95 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.Sets; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.ex.CompilerPathsEx; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTraceContext; + +import java.util.Set; /** * @author abreslav */ public class AnalyzerFacade { + + private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); + private final static Key> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); + private static final Object lock = new Object(); + public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { - return AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespace(namespace, flowDataTraceFactory); + return ANALYZING_UTILS.analyzeNamespace(namespace, flowDataTraceFactory); } - public static BindingContext analyzeFileWithCache(@NotNull JetFile file) { - return AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeFileWithCache(file); + public static BindingContext analyzeFileWithCache(@NotNull final JetFile file) { + return analyzeFileWithCache(ANALYZING_UTILS, file); } + public static BindingContext analyzeFileWithCache(@NotNull final AnalyzingUtils analyzingUtils, @NotNull final JetFile file) { + // TODO : Synchronization? + CachedValue bindingContextCachedValue = file.getUserData(BINDING_CONTEXT); + if (bindingContextCachedValue == null) { + bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + synchronized (lock) { + final Project project = file.getProject(); + final Set namespaces = Sets.newLinkedHashSet(); + ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { + VirtualFile[] contentRoots = rootManager.getContentRoots(); + + CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { + @Override + protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { + if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile instanceof JetFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + }); + } + else { + namespaces.add(file.getRootNamespace()); + } + try { + BindingContext bindingContext = analyzingUtils.analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); + return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable e) { + e.printStackTrace(); + BindingTraceContext bindingTraceContext = new BindingTraceContext(); + bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e)); + return new Result(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT); + } + } + } + }, false); + file.putUserData(BINDING_CONTEXT, bindingContextCachedValue); + } + return bindingContextCachedValue.getValue(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 70178295035..ade95c7d747 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -1,18 +1,9 @@ package org.jetbrains.jet.lang.resolve; -import com.google.common.collect.Lists; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.ex.CompilerPathsEx; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.util.Key; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.util.CachedValue; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiErrorElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; @@ -20,27 +11,20 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; -import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; +import java.util.Collection; import java.util.Collections; import java.util.List; -//import org.jetbrains.jet.lang.resolve.java.JavaPackageScope; -//import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; - /** * @author abreslav */ public class AnalyzingUtils { - private final static Key> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); - private static final Object lock = new Object(); - public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) { return new AnalyzingUtils(importingStrategy); } @@ -78,7 +62,7 @@ public class AnalyzingUtils { return analyzeNamespaces(project, declarations, flowDataTraceFactory); } - public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { + public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull Collection declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); @@ -121,54 +105,4 @@ public class AnalyzingUtils { return bindingTraceContext.getBindingContext(); } - public BindingContext analyzeFileWithCache(@NotNull final JetFile file) { - // TODO : Synchronization? - CachedValue bindingContextCachedValue = file.getUserData(BINDING_CONTEXT); - if (bindingContextCachedValue == null) { - bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - synchronized (lock) { - final Project project = file.getProject(); - final List namespaces = Lists.newArrayList(); - ProjectRootManager rootManager = ProjectRootManager.getInstance(project); - if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { - VirtualFile[] contentRoots = rootManager.getContentRoots(); - - CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { - @Override - protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { - if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); - } - } - }); - } - else { - namespaces.add(file.getRootNamespace()); - } - try { -// JetNamespace rootNamespace = file.getRootNamespace(); - BindingContext bindingContext = analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); - return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Throwable e) { - e.printStackTrace(); - BindingTraceContext bindingTraceContext = new BindingTraceContext(); -// bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage()); - bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e)); - return new Result(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT); - } - } - } - }, false); - file.putUserData(BINDING_CONTEXT, bindingContextCachedValue); - } - return bindingContextCachedValue.getValue(); - } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 3b43c0bbe42..e0cf26bce1b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -4,12 +4,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.psi.JetObjectDeclaration; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import java.util.Collection; import java.util.Collections; -import java.util.List; /** * @author abreslav @@ -23,7 +26,7 @@ public class TopDownAnalyzer { @NotNull BindingTrace trace, @NotNull JetScope outerScope, NamespaceLike owner, - @NotNull List declarations, + @NotNull Collection declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false); } @@ -33,7 +36,7 @@ public class TopDownAnalyzer { @NotNull BindingTrace trace, @NotNull JetScope outerScope, NamespaceLike owner, - @NotNull List declarations, + @NotNull Collection declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, boolean declaredLocally) { TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 49ed44b4a4f..0b7dc1377a1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -36,7 +36,7 @@ public class TypeHierarchyResolver { this.context = context; } - public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List declarations) { + public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull Collection declarations) { collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes processTypeImports(); diff --git a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java index 319e0b06789..5ed457a6212 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.ImportingStrategy; +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import java.util.Collections; import java.util.List; @@ -80,7 +81,7 @@ public class CheckerTestUtilTest extends JetLiteFixture { } public void test(PsiFile psiFile) { - BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache((JetFile) psiFile); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile); String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); List diagnosedRanges = Lists.newArrayList(); diff --git a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java index ebb5e91515e..8256b2d1b01 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.ImportingStrategy; +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import java.util.List; @@ -39,7 +40,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture { createAndCheckPsiFile(name, clearText); JetFile jetFile = (JetFile) myFile; - BindingContext bindingContext = AnalyzingUtils.getInstance(ImportingStrategy.NONE).analyzeFileWithCache(jetFile); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), jetFile); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override From 57bba593ae789dd3903a4560ed904ef5ce5ea49c Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 30 Oct 2011 12:22:03 +0300 Subject: [PATCH 16/31] Fixing dependencies: moved the code that walks through project files into the plugin --- .../jet/lang/resolve/java/AnalyzerFacade.java | 53 +++++++---------- .../jet/checkers/CheckerTestUtilTest.java | 2 +- .../jet/checkers/FullJetPsiCheckerTest.java | 2 +- .../jet/checkers/QuickJetPsiCheckerTest.java | 2 +- .../JetDefaultModalityModifiersTest.java | 2 +- .../plugin/JetQuickDocumentationProvider.java | 3 +- .../actions/CopyAsDiagnosticTestAction.java | 3 +- .../actions/ShowExpressionTypeAction.java | 4 +- .../annotations/DebugInfoAnnotator.java | 3 +- .../annotations/JetLineMarkerProvider.java | 4 +- .../jet/plugin/annotations/JetPsiChecker.java | 3 +- .../compiler/WholeProjectAnalyzerFacade.java | 57 +++++++++++++++++++ .../plugin/debugger/JetPositionManager.java | 4 +- .../plugin/references/JetPsiReference.java | 6 +- .../references/JetSimpleNameReference.java | 6 +- 15 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java index 867cf723b8a..b14585f1d4d 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java @@ -1,19 +1,12 @@ package org.jetbrains.jet.lang.resolve.java; -import com.google.common.collect.Sets; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.ex.CompilerPathsEx; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Key; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; +import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.diagnostics.Errors; @@ -24,13 +17,21 @@ import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import java.util.Set; +import java.util.Collection; +import java.util.Collections; /** * @author abreslav */ public class AnalyzerFacade { + public static final Function> SINGLE_DECLARATION_PROVIDER = new Function>() { + @Override + public Collection fun(JetFile file) { + return Collections.singleton(file.getRootNamespace()); + } + }; + private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); private final static Key> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); private static final Object lock = new Object(); @@ -39,11 +40,13 @@ public class AnalyzerFacade { return ANALYZING_UTILS.analyzeNamespace(namespace, flowDataTraceFactory); } - public static BindingContext analyzeFileWithCache(@NotNull final JetFile file) { - return analyzeFileWithCache(ANALYZING_UTILS, file); + public static BindingContext analyzeFileWithCache(@NotNull final JetFile file, @NotNull final Function> declarationProvider) { + return analyzeFileWithCache(ANALYZING_UTILS, file, declarationProvider); } - public static BindingContext analyzeFileWithCache(@NotNull final AnalyzingUtils analyzingUtils, @NotNull final JetFile file) { + public static BindingContext analyzeFileWithCache(@NotNull final AnalyzingUtils analyzingUtils, + @NotNull final JetFile file, + @NotNull final Function> declarationProvider) { // TODO : Synchronization? CachedValue bindingContextCachedValue = file.getUserData(BINDING_CONTEXT); if (bindingContextCachedValue == null) { @@ -51,28 +54,11 @@ public class AnalyzerFacade { @Override public Result compute() { synchronized (lock) { - final Project project = file.getProject(); - final Set namespaces = Sets.newLinkedHashSet(); - ProjectRootManager rootManager = ProjectRootManager.getInstance(project); - if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { - VirtualFile[] contentRoots = rootManager.getContentRoots(); - - CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { - @Override - protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { - if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); - } - } - }); - } - else { - namespaces.add(file.getRootNamespace()); - } try { - BindingContext bindingContext = analyzingUtils.analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); + BindingContext bindingContext = analyzingUtils.analyzeNamespaces( + file.getProject(), + declarationProvider.fun(file), + JetControlFlowDataTraceFactory.EMPTY); return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); } catch (ProcessCanceledException e) { @@ -86,6 +72,7 @@ public class AnalyzerFacade { } } } + }, false); file.putUserData(BINDING_CONTEXT, bindingContextCachedValue); } diff --git a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java index 5ed457a6212..06ffed74d04 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java @@ -81,7 +81,7 @@ public class CheckerTestUtilTest extends JetLiteFixture { } public void test(PsiFile psiFile) { - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), (JetFile) psiFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); List diagnosedRanges = Lists.newArrayList(); diff --git a/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java index a5fdd26d6ac..986f6501d10 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/FullJetPsiCheckerTest.java @@ -42,7 +42,7 @@ public class FullJetPsiCheckerTest extends JetLiteFixture { String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges); myFile = createPsiFile(myName, clearText); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(myFile); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(myFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override diff --git a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java index 8256b2d1b01..d6ead64cdf1 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java +++ b/compiler/tests/org/jetbrains/jet/checkers/QuickJetPsiCheckerTest.java @@ -40,7 +40,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture { createAndCheckPsiFile(name, clearText); JetFile jetFile = (JetFile) myFile; - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), jetFile); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(AnalyzingUtils.getInstance(ImportingStrategy.NONE), jetFile, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override diff --git a/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java b/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java index 5547eab74bc..bb86813770e 100644 --- a/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java +++ b/compiler/tests/org/jetbrains/jet/types/JetDefaultModalityModifiersTest.java @@ -44,7 +44,7 @@ public class JetDefaultModalityModifiersTest extends JetLiteFixture { List declarations = file.getRootNamespace().getDeclarations(); JetDeclaration aClass = declarations.get(0); assert aClass instanceof JetClass; - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); DeclarationDescriptor classDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass); WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING); assert classDescriptor instanceof ClassifierDescriptor; diff --git a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java index bdcca23ba32..6108b7e0006 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java @@ -9,6 +9,7 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.resolve.DescriptorRenderer; /** @@ -26,7 +27,7 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider ref = PsiTreeUtil.getParentOfType(originalElement, JetReferenceExpression.class); } if (ref != null) { - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) element.getContainingFile()); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) element.getContainingFile()); DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, ref); if (declarationDescriptor != null) { return render(declarationDescriptor); diff --git a/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java b/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java index 6672b66de6e..7e3844b4c4d 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/CopyAsDiagnosticTestAction.java @@ -11,6 +11,7 @@ import org.jetbrains.jet.checkers.CheckerTestUtil; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import java.awt.*; import java.awt.datatransfer.Clipboard; @@ -28,7 +29,7 @@ public class CopyAsDiagnosticTestAction extends AnAction { PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); assert editor != null && psiFile != null; - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile); String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); diff --git a/idea/src/org/jetbrains/jet/plugin/actions/ShowExpressionTypeAction.java b/idea/src/org/jetbrains/jet/plugin/actions/ShowExpressionTypeAction.java index 4611f9cc010..421bc953071 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/ShowExpressionTypeAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/ShowExpressionTypeAction.java @@ -12,9 +12,9 @@ import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetLanguage; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; /** * @author yole @@ -26,7 +26,7 @@ public class ShowExpressionTypeAction extends AnAction { PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); assert editor != null && psiFile != null; JetExpression expression; - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile); if (editor.getSelectionModel().hasSelection()) { int startOffset = editor.getSelectionModel().getSelectionStart(); int endOffset = editor.getSelectionModel().getSelectionEnd(); diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java index 9c6702b742c..f4947190f67 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/DebugInfoAnnotator.java @@ -20,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetHighlighter; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import java.util.Collection; import java.util.Set; @@ -53,7 +54,7 @@ public class DebugInfoAnnotator implements Annotator { if (element instanceof JetFile) { JetFile file = (JetFile) element; try { - final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); final Set unresolvedReferences = Sets.newHashSet(); for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java index 299adbff7dc..d3782840dd5 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetLineMarkerProvider.java @@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull; 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.java.AnalyzerFacade; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.resolve.DescriptorRenderer; import javax.swing.*; @@ -45,7 +45,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { JetFile file = PsiTreeUtil.getParentOfType(element, JetFile.class); if (file == null) return null; - final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); if (element instanceof JetClass) { JetClass jetClass = (JetClass) element; diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index 34ae7bf85ea..59e3586d793 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetHighlighter; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.quickfix.JetIntentionActionFactory; import org.jetbrains.jet.plugin.quickfix.QuickFixes; @@ -54,7 +55,7 @@ public class JetPsiChecker implements Annotator { JetFile file = (JetFile) element; Project project = element.getProject(); try { - final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); if (errorReportingEnabled) { Collection diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java new file mode 100644 index 00000000000..d6af8ce2118 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -0,0 +1,57 @@ +package org.jetbrains.jet.plugin.compiler; + +import com.google.common.collect.Sets; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.compiler.ex.CompilerPathsEx; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; + +import java.util.Collection; +import java.util.Set; + +/** + * @author abreslav + */ +public class WholeProjectAnalyzerFacade { + public static final Function> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function>() { + @Override + public Collection fun(JetFile file) { + final Project project = file.getProject(); + final Set namespaces = Sets.newLinkedHashSet(); + ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { + VirtualFile[] contentRoots = rootManager.getContentRoots(); + + CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { + @Override + protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { + if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile instanceof JetFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + }); + } + else { + namespaces.add(file.getRootNamespace()); + } + return namespaces; + } + }; + + @NotNull + public static BindingContext analyzeProjectWithCacheOnAFile(@NotNull JetFile file) { + return AnalyzerFacade.analyzeFileWithCache(file, WHOLE_PROJECT_DECLARATION_PROVIDER); + } + +} diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java index f22310cf037..567f51efca5 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java +++ b/idea/src/org/jetbrains/jet/plugin/debugger/JetPositionManager.java @@ -21,8 +21,8 @@ import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import java.util.*; @@ -125,7 +125,7 @@ public class JetPositionManager implements PositionManager { if (mapper != null) { return mapper; } - final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(myDebugProcess.getProject()); final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext); file.acceptChildren(new JetVisitorVoid() { diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java index 220bc1923d3..417506355ff 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetPsiReference.java @@ -12,7 +12,7 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl; -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import java.util.Collection; @@ -76,7 +76,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { protected PsiElement doResolve() { JetFile file = (JetFile) getElement().getContainingFile(); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, myExpression); if (psiElement != null) { return psiElement; @@ -88,7 +88,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference { protected ResolveResult[] doMultiResolve() { JetFile file = (JetFile) getElement().getContainingFile(); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); Collection> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY; ResolveResult[] results = new ResolveResult[resolvedCalls.size()]; diff --git a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java index 85b0ee34e89..49cead70134 100644 --- a/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java +++ b/idea/src/org/jetbrains/jet/plugin/references/JetSimpleNameReference.java @@ -13,9 +13,9 @@ import org.jetbrains.annotations.NotNull; 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.java.AnalyzerFacade; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.resolve.DescriptorRenderer; import java.util.List; @@ -51,7 +51,7 @@ class JetSimpleNameReference extends JetPsiReference { JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent; JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); JetFile file = (JetFile) myExpression.getContainingFile(); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiverExpression); if (expressionType != null) { return collectLookupElements(bindingContext, expressionType.getMemberScope()); @@ -59,7 +59,7 @@ class JetSimpleNameReference extends JetPsiReference { } else { JetFile file = (JetFile) myExpression.getContainingFile(); - BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, myExpression); if (resolutionScope != null) { return collectLookupElements(bindingContext, resolutionScope); From c92b1ae9724bc3475351fa016274f5d6bedfa9fa Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 31 Oct 2011 14:36:52 +0300 Subject: [PATCH 17/31] Proposal for Code Generation 2012, initial version --- docs/CodeGen2012_Proposal.txt | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 docs/CodeGen2012_Proposal.txt diff --git a/docs/CodeGen2012_Proposal.txt b/docs/CodeGen2012_Proposal.txt new file mode 100644 index 00000000000..5189b15d3a5 --- /dev/null +++ b/docs/CodeGen2012_Proposal.txt @@ -0,0 +1,64 @@ +Code Generation 2012 - Session Proposal Form + +Submission Deadline: Friday December 9th 2011 + +Session title: +Creating DSLs in Kotlin + +Session type and duration: +Tutorial, 60 min + +Session abstract: +This should be a brief description of the session focusing on its content and objectives. You will need to cut and paste this text into a web form as part of the submission process. The session abstract will be used on the event web site to promote your session. + +Kotlin is a statically typed programming language for the JVM proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. One can even mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin. + +In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes covering many interesting language features such as +* type inference, +* function literals (closures), +* operator overloading/overriding, +* extension functions +* and more… + +As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Along with this example we'll demonstrate LINQ-like collection processing and a DSL for program module definitions. + +Benefits of participating: +What will participants get out of taking part in the session? It is very important to think about this and describe it in your proposal. + +Process & timetable: +How will the session work? You might want to describe any exercises or group working. Consider providing a detailed timetable. Indicate the way in which the audience is involved. + +Session outputs: +Indicate the form of any outputs (e.g. web page, poster at conference, blog posting etc) and their likely content (summary, actions points etc.) + +Intended Audience: +Note any required skills/knowledge/ experience. What job roles would this session be particularly applicable to. + +Availability: +Indicate if there are any constraints in your participation or whether it makes sense to run your session before or after another session you've proposed + +Detailed Description / Supporting Information +A fuller description of the session describing the content, rationale and describing any previous occasions on which the session has been run. + +Main presenter name, contact details and biography + +Name: +Affiliation: +Telephone / Skype: +Email: +Biography (up to 100 words): + +Additional Presenter(s) (if any) +Name: +Affiliation: +Telephone / Skype: +Email: +Biography (up to 100 words): + +Name: +Affiliation: +Telephone / Skype: +Email: +Biography (up to 100 words): + + From f6bb7e34ff365576143b59750f9365ae05246d36 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Mon, 31 Oct 2011 14:44:49 +0300 Subject: [PATCH 18/31] Don't rely on hardcoded file extensions. --- .../jet/plugin/compiler/WholeProjectAnalyzerFacade.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java index d6af8ce2118..f9a93b42999 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -3,6 +3,8 @@ package org.jetbrains.jet.plugin.compiler; import com.google.common.collect.Sets; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.ex.CompilerPathsEx; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; @@ -14,6 +16,7 @@ import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; +import org.jetbrains.jet.plugin.JetFileType; import java.util.Collection; import java.util.Set; @@ -34,7 +37,8 @@ public class WholeProjectAnalyzerFacade { CompilerPathsEx.visitFiles(contentRoots, new CompilerPathsEx.FileVisitor() { @Override protected void acceptFile(VirtualFile file, String fileRoot, String filePath) { - if (!(file.getName().endsWith(".kt") || file.getName().endsWith(".kts"))) return; + final FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(file); + if (fileType != JetFileType.INSTANCE) return; PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof JetFile) { namespaces.add(((JetFile) psiFile).getRootNamespace()); From 68ceb9570d0a5764a5c7ce9ec44d54b0438e4f10 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Mon, 31 Oct 2011 15:16:30 +0300 Subject: [PATCH 19/31] Completion's file copy missed "whole project" analysis train --- .../compiler/WholeProjectAnalyzerFacade.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java index f9a93b42999..01d853c9d7d 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -27,8 +27,8 @@ import java.util.Set; public class WholeProjectAnalyzerFacade { public static final Function> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function>() { @Override - public Collection fun(JetFile file) { - final Project project = file.getProject(); + public Collection fun(final JetFile rootFile) { + final Project project = rootFile.getProject(); final Set namespaces = Sets.newLinkedHashSet(); ProjectRootManager rootManager = ProjectRootManager.getInstance(project); if (rootManager != null && !ApplicationManager.getApplication().isUnitTestMode()) { @@ -41,16 +41,18 @@ public class WholeProjectAnalyzerFacade { if (fileType != JetFileType.INSTANCE) return; PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); + if (rootFile.getOriginalFile() != psiFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } } } }); + } - else { - namespaces.add(file.getRootNamespace()); - } + + namespaces.add(rootFile.getRootNamespace()); return namespaces; - } + } }; @NotNull From 344dea0ad580e305da1e415583bdccca2a168e67 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 28 Oct 2011 21:17:09 +0200 Subject: [PATCH 20/31] extact CompileSession class; work in progress on module compilation --- .../org/jetbrains/jet/cli/CompileSession.java | 97 +++++++ .../org/jetbrains/jet/cli/ErrorCollector.java | 52 ++++ .../org/jetbrains/jet/cli/KotlinCompiler.java | 238 ++++++++---------- examples/src/Hello.kts | 6 +- 4 files changed, 253 insertions(+), 140 deletions(-) create mode 100644 compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java create mode 100644 compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java diff --git a/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java new file mode 100644 index 00000000000..90807c39b91 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java @@ -0,0 +1,97 @@ +package org.jetbrains.jet.cli; + +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.ClassFileFactory; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.resolve.AnalyzingUtils; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; +import org.jetbrains.jet.plugin.JetFileType; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author yole + */ +public class CompileSession { + private final JetCoreEnvironment myEnvironment; + private final List mySourceFileNamespaces = new ArrayList(); + private final List myLibrarySourceFileNamespaces = new ArrayList(); + private List myErrors = new ArrayList(); + private BindingContext myBindingContext; + + public CompileSession(JetCoreEnvironment environment) { + myEnvironment = environment; + } + + public void addSources(String path) { + VirtualFile vFile = myEnvironment.getLocalFileSystem().findFileByPath(path); + if (vFile == null) { + myErrors.add("File/directory not found: " + path); + return; + } + if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) { + myErrors.add("Not a Kotlin file: " + path); + return; + } + + addSources(vFile); + } + + public void addSources(VirtualFile vFile) { + if (vFile.isDirectory()) { + for (VirtualFile virtualFile : vFile.getChildren()) { + if (virtualFile.getFileType() == JetFileType.INSTANCE) { + addSources(virtualFile); + } + } + } + else { + PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile); + if (psiFile instanceof JetFile) { + mySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + } + + public void addLibrarySources(VirtualFile vFile) { + PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile); + if (psiFile instanceof JetFile) { + myLibrarySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + + public List getSourceFileNamespaces() { + return mySourceFileNamespaces; + } + + public boolean analyze() { + if (!myErrors.isEmpty()) { + for (String error : myErrors) { + System.out.println(error); + } + return false; + } + final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); + List allNamespaces = new ArrayList(mySourceFileNamespaces); + allNamespaces.addAll(myLibrarySourceFileNamespaces); + myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, JetControlFlowDataTraceFactory.EMPTY); + ErrorCollector errorCollector = new ErrorCollector(myBindingContext); + errorCollector.report(); + return !errorCollector.hasErrors; + } + + public ClassFileFactory generate() { + GenerationState generationState = new GenerationState(myEnvironment.getProject(), false); + generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces); + return generationState.getFactory(); + } + +} diff --git a/compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java b/compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java new file mode 100644 index 00000000000..1da315a1b80 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/ErrorCollector.java @@ -0,0 +1,52 @@ +package org.jetbrains.jet.cli; + +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.intellij.psi.PsiFile; +import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange; +import org.jetbrains.jet.lang.diagnostics.Severity; +import org.jetbrains.jet.lang.resolve.BindingContext; + +import java.util.Collection; + +/** +* @author alex.tkachman +*/ +class ErrorCollector { + Multimap maps = LinkedHashMultimap.create(); + + boolean hasErrors; + + public ErrorCollector(BindingContext bindingContext) { + for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { + report(diagnostic); + } + } + + private void report(Diagnostic diagnostic) { + hasErrors |= diagnostic.getSeverity() == Severity.ERROR; + if(diagnostic instanceof DiagnosticWithTextRange) { + DiagnosticWithTextRange diagnosticWithTextRange = (DiagnosticWithTextRange) diagnostic; + maps.put(diagnosticWithTextRange.getPsiFile(), diagnosticWithTextRange); + } + else { + System.out.println(diagnostic.getSeverity().toString() + ": " + diagnostic.getMessage()); + } + } + + void report() { + if(!maps.isEmpty()) { + for (PsiFile psiFile : maps.keySet()) { + System.out.println(psiFile.getVirtualFile().getPath()); + Collection diagnosticWithTextRanges = maps.get(psiFile); + for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) { + String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange); + System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage()); + } + } + } + } + +} diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 1f60ab2269b..e391db30564 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -1,31 +1,16 @@ package org.jetbrains.jet.cli; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.intellij.core.JavaCoreEnvironment; import com.intellij.openapi.Disposable; -import com.intellij.openapi.project.Project; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; import com.intellij.util.Processor; import com.sampullara.cli.Args; import com.sampullara.cli.Argument; import org.jetbrains.jet.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; -import org.jetbrains.jet.codegen.GenerationState; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.diagnostics.Diagnostic; -import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange; -import org.jetbrains.jet.lang.diagnostics.Severity; -import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetNamespace; -import org.jetbrains.jet.lang.resolve.AnalyzingUtils; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import org.jetbrains.jet.plugin.JetMainDetector; import java.io.File; @@ -34,7 +19,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; -import java.util.Collection; import java.util.List; import java.util.jar.*; @@ -49,8 +33,10 @@ public class KotlinCompiler { public String outputDir; @Argument(value = "jar", description = "jar file name") public String jar; - @Argument(value = "src", description = "source file or directory", required = true) + @Argument(value = "src", description = "source file or directory") public String src; + @Argument(value = "module", description = "module to compile") + public String module; } public static void main(String[] args) { @@ -76,56 +62,70 @@ public class KotlinCompiler { if (rtJar == null) return; environment.addToClasspath(rtJar); + final File unpackedRuntimePath = getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + environment.addToClasspath(unpackedRuntimePath); + } - VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(arguments.src); - if (vFile == null) { - System.out.print("File/directory not found: " + arguments.src); + if (arguments.module != null) { + compileModule(environment, arguments.module); return; } - Project project = environment.getProject(); - GenerationState generationState = new GenerationState(project, false); - List namespaces = Lists.newArrayList(); + CompileSession session = new CompileSession(environment); + session.addSources(arguments.src); + String mainClass = null; - if(vFile.isDirectory()) { - File dir = new File(vFile.getPath()); - addFiles(environment, project, namespaces, dir); + for (JetNamespace namespace : session.getSourceFileNamespaces()) { + if (JetMainDetector.hasMain(namespace.getDeclarations())) { + mainClass = namespace.getFQName() + ".namespace"; + break; + } + } + if (!session.analyze()) { + return; + } + + ClassFileFactory factory = session.generate(); + if (arguments.jar != null) { + writeToJar(factory, arguments.jar, mainClass, true); + } + else if (arguments.outputDir != null) { + writeToOutputDirectory(factory, arguments.outputDir); } else { - PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile); - if (psiFile instanceof JetFile) { - final JetNamespace namespace = ((JetFile) psiFile).getRootNamespace(); - if (JetMainDetector.hasMain(namespace.getDeclarations())) { - mainClass = namespace.getFQName() + ".namespace"; - } - namespaces.add(namespace); - } - else { - System.out.print("Not a Kotlin file: " + vFile.getPath()); - return; - } + System.out.println("Output directory or jar file is not specified - no files will be saved to the disk"); + } + } + + private static void compileModule(JetCoreEnvironment environment, String moduleFile) { + final FileIndexFacade instance = FileIndexFacade.getInstance(environment.getProject()); + VirtualFile jetObject = environment.getLocalFileSystem().findFileByPath(KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class").getPath()); + instance.isInLibraryClasses(jetObject); + + CompileSession moduleCompileSession = new CompileSession(environment); + moduleCompileSession.addSources(moduleFile); + + URL url = KotlinCompiler.class.getClassLoader().getResource("ModuleBuilder.kt"); + if (url != null) { + // TODO + } + else { + // building from source + final String homeDirectory = getHomeDirectory(); + final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); + moduleCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); + } - BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); - - ErrorCollector errorCollector = new ErrorCollector(bindingContext); - errorCollector.report(); - - if (!errorCollector.hasErrors) { - generationState.compileCorrectNamespaces(bindingContext, namespaces); - - final ClassFileFactory factory = generationState.getFactory(); - if (arguments.jar != null) { - writeToJar(factory, arguments.jar, mainClass, true); - } - else if (arguments.outputDir != null) { - writeToOutputDirectory(factory, arguments.outputDir); - } - else { - System.out.println("Output directory or jar file is not specified - no files will be saved to the disk"); - } + if (!moduleCompileSession.analyze()) { + return; } + final ClassFileFactory factory = moduleCompileSession.generate(); + } + private static String getHomeDirectory() { + return new File(PathManager.getResourceRoot(KotlinCompiler.class, "/org/jetbrains/jet/cli/KotlinCompiler.class")).getParentFile().getParentFile().getParent(); } private static void writeToJar(ClassFileFactory factory, String jar, String mainClass, boolean includeRuntime) { @@ -157,22 +157,32 @@ public class KotlinCompiler { System.out.println("Failed to generate jar file: " + e.getMessage()); } } + + private static File getUnpackedRuntimePath() { + URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("file")) { + return new File(url.getPath()).getParentFile().getParentFile(); + } + return null; + } + + private static File getRuntimeJarPath() { + URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("jar")) { + String path = url.getPath(); + return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); + } + return null; + } private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException { - URL url = KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class"); - if (url == null) { - System.out.println("Couldn't find runtime library"); - return; - } - final String protocol = url.getProtocol(); - final String path = url.getPath(); - if (protocol.equals("file")) { // unpacked runtime - final File stdlibDir = new File(path).getParentFile().getParentFile(); - FileUtil.processFilesRecursively(stdlibDir, new Processor() { + final File unpackedRuntimePath = getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor() { @Override public boolean process(File file) { if (file.isDirectory()) return true; - final String relativePath = FileUtil.getRelativePath(stdlibDir, file); + final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file); try { stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath))); FileInputStream fis = new FileInputStream(file); @@ -188,24 +198,28 @@ public class KotlinCompiler { } }); } - else if (protocol.equals("jar")) { - File jar = new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); - JarInputStream jis = new JarInputStream(new FileInputStream(jar)); - try { - while (true) { - JarEntry e = jis.getNextJarEntry(); - if (e == null) { - break; - } - stream.putNextEntry(e); - FileUtil.copy(jis, stream); - } - } finally { - jis.close(); - } - } else { - System.out.println("Couldn't copy runtime library from " + url + ", protocol " + protocol); + File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null) { + JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath)); + try { + while (true) { + JarEntry e = jis.getNextJarEntry(); + if (e == null) { + break; + } + if (FileUtil.getExtension(e.getName()).equals("class")) { + stream.putNextEntry(e); + FileUtil.copy(jis, stream); + } + } + } finally { + jis.close(); + } + } + else { + System.out.println("Couldn't find runtime library"); + } } } @@ -222,58 +236,6 @@ public class KotlinCompiler { } } - private static class ErrorCollector { - Multimap maps = LinkedHashMultimap.create(); - - boolean hasErrors; - - public ErrorCollector(BindingContext bindingContext) { - for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { - report(diagnostic); - } - } - - private void report(Diagnostic diagnostic) { - hasErrors |= diagnostic.getSeverity() == Severity.ERROR; - if(diagnostic instanceof DiagnosticWithTextRange) { - DiagnosticWithTextRange diagnosticWithTextRange = (DiagnosticWithTextRange) diagnostic; - maps.put(diagnosticWithTextRange.getPsiFile(), diagnosticWithTextRange); - } - else { - System.out.println(diagnostic.getSeverity().toString() + ": " + diagnostic.getMessage()); - } - } - - void report() { - if(!maps.isEmpty()) { - for (PsiFile psiFile : maps.keySet()) { - System.out.println(psiFile.getVirtualFile().getPath()); - Collection diagnosticWithTextRanges = maps.get(psiFile); - for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) { - String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange); - System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage()); - } - } - } - } - - } - - private static void addFiles(JavaCoreEnvironment environment, Project project, List namespaces, File dir) { - for(File file : dir.listFiles()) { - if(!file.isDirectory()) { - VirtualFile virtualFile = environment.getLocalFileSystem().findFileByPath(file.getAbsolutePath()); - PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); - if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); - } - } - else { - addFiles(environment, project, namespaces, file); - } - } - } - private static File initJdk() { String javaHome = System.getenv("JAVA_HOME"); File rtJar = null; diff --git a/examples/src/Hello.kts b/examples/src/Hello.kts index 936a1694ffc..c7086636e56 100644 --- a/examples/src/Hello.kts +++ b/examples/src/Hello.kts @@ -1,5 +1,7 @@ import kotlin.modules.ModuleSetBuilder fun defineModules(builder: ModuleSetBuilder) { - -} \ No newline at end of file + builder.module("hello") { + source files "HelloNames.kt" + } +} From b39ea7a876cfd4af6f06b82c50a373e7d0488f69 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 31 Oct 2011 13:35:18 +0100 Subject: [PATCH 21/31] module compiler: initial working version --- build.xml | 1 + .../jet/codegen/GeneratedClassLoader.java | 23 +++++ compiler/cli/cli.iml | 1 + .../org/jetbrains/jet/cli/KotlinCompiler.java | 91 ++++++++++++++++--- .../jet/codegen/CodegenTestCase.java | 21 +---- stdlib/ktSrc/ModuleBuilder.kt | 8 +- stdlib/src/jet/modules/IModuleBuilder.java | 1 + stdlib/src/jet/modules/IModuleSetBuilder.java | 10 ++ 8 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java create mode 100644 stdlib/src/jet/modules/IModuleSetBuilder.java diff --git a/build.xml b/build.xml index c5a74ee9208..bc0ee63e9f7 100644 --- a/build.xml +++ b/build.xml @@ -29,6 +29,7 @@ + diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java new file mode 100644 index 00000000000..b851b21a8a0 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedClassLoader.java @@ -0,0 +1,23 @@ +package org.jetbrains.jet.codegen; + +/** +* @author yole +*/ +public class GeneratedClassLoader extends ClassLoader { + private final ClassFileFactory state; + + public GeneratedClassLoader(ClassFileFactory state) { + super(GeneratedClassLoader.class.getClassLoader()); + this.state = state; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + String file = name.replace('.', '/') + ".class"; + if (state.files().contains(file)) { + byte[] bytes = state.asBytes(file); + return defineClass(name, bytes, 0, bytes.length); + } + return super.findClass(name); + } +} diff --git a/compiler/cli/cli.iml b/compiler/cli/cli.iml index de82ce75e19..ed2341d3d46 100644 --- a/compiler/cli/cli.iml +++ b/compiler/cli/cli.iml @@ -10,6 +10,7 @@ + diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index e391db30564..7f047272fe2 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -2,14 +2,16 @@ package org.jetbrains.jet.cli; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.PathManager; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Processor; import com.sampullara.cli.Args; import com.sampullara.cli.Argument; +import jet.modules.IModuleBuilder; +import jet.modules.IModuleSetBuilder; import org.jetbrains.jet.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassFileFactory; +import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.plugin.JetMainDetector; @@ -17,6 +19,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.List; @@ -66,9 +69,19 @@ public class KotlinCompiler { if (unpackedRuntimePath != null) { environment.addToClasspath(unpackedRuntimePath); } + else { + final File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null && runtimeJarPath.exists()) { + environment.addToClasspath(runtimeJarPath); + } + else { + System.out.println("No runtime library found"); + return; + } + } if (arguments.module != null) { - compileModule(environment, arguments.module); + compileModuleScript(environment, arguments.module); return; } @@ -98,30 +111,82 @@ public class KotlinCompiler { } } - private static void compileModule(JetCoreEnvironment environment, String moduleFile) { - final FileIndexFacade instance = FileIndexFacade.getInstance(environment.getProject()); - VirtualFile jetObject = environment.getLocalFileSystem().findFileByPath(KotlinCompiler.class.getClassLoader().getResource("jet/JetObject.class").getPath()); - instance.isInLibraryClasses(jetObject); - - CompileSession moduleCompileSession = new CompileSession(environment); - moduleCompileSession.addSources(moduleFile); + private static void compileModuleScript(JetCoreEnvironment environment, String moduleFile) { + CompileSession scriptCompileSession = new CompileSession(environment); + scriptCompileSession.addSources(moduleFile); URL url = KotlinCompiler.class.getClassLoader().getResource("ModuleBuilder.kt"); if (url != null) { - // TODO + String path = url.getPath(); + if (path.startsWith("file:")) { + path = path.substring(5); + } + final VirtualFile vFile = environment.getJarFileSystem().findFileByPath(path); + if (vFile == null) { + System.out.println("Couldn't load ModuleBuilder.kt from runtime jar: "+ url); + return; + } + scriptCompileSession.addSources(vFile); } else { // building from source final String homeDirectory = getHomeDirectory(); final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); - moduleCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); - + scriptCompileSession.addSources(environment.getLocalFileSystem().findFileByPath(file.getPath())); } + if (!scriptCompileSession.analyze()) { + return; + } + final ClassFileFactory factory = scriptCompileSession.generate(); + + final IModuleSetBuilder moduleSetBuilder = runDefineModules(moduleFile, factory); + + for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { + compileModule(environment, moduleBuilder, new File(moduleFile).getParent()); + } + } + + private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) { + GeneratedClassLoader loader = new GeneratedClassLoader(factory); + try { + Class moduleSetBuilderClass = loader.loadClass("kotlin.modules.ModuleSetBuilder"); + final IModuleSetBuilder moduleSetBuilder = (IModuleSetBuilder) moduleSetBuilderClass.newInstance(); + + Class namespaceClass = loader.loadClass("namespace"); + final Method[] methods = namespaceClass.getMethods(); + boolean modulesDefined = false; + for (Method method : methods) { + if (method.getName().equals("defineModules")) { + method.invoke(null, moduleSetBuilder); + modulesDefined = true; + break; + } + } + if (!modulesDefined) { + System.out.println("Module script " + moduleFile + " must define a defineModules() method"); + return null; + } + return moduleSetBuilder; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private static void compileModule(JetCoreEnvironment environment, IModuleBuilder moduleBuilder, String directory) { + CompileSession moduleCompileSession = new CompileSession(environment); + for (String sourceFile : moduleBuilder.getSourceFiles()) { + moduleCompileSession.addSources(new File(directory, sourceFile).getPath()); + } + for (String classpathRoot : moduleBuilder.getClasspathRoots()) { + environment.addToClasspath(new File(classpathRoot)); + } if (!moduleCompileSession.analyze()) { return; } - final ClassFileFactory factory = moduleCompileSession.generate(); + ClassFileFactory factory = moduleCompileSession.generate(); + writeToJar(factory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); } private static String getHomeDirectory() { diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 8b0bb54a270..e6ec1009270 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -88,7 +88,7 @@ public abstract class CodegenTestCase extends JetLiteFixture { protected String blackBox() throws Exception { ClassFileFactory codegens = generateClassesInFile(); - CodegensClassLoader loader = new CodegensClassLoader(codegens); + GeneratedClassLoader loader = new GeneratedClassLoader(codegens); final JetNamespace namespace = myFile.getRootNamespace(); String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."); @@ -215,23 +215,4 @@ public abstract class CodegenTestCase extends JetLiteFixture { return super.loadClass(name); } } - - private static class CodegensClassLoader extends ClassLoader { - private final ClassFileFactory state; - - public CodegensClassLoader(ClassFileFactory state) { - super(CodegenTestCase.class.getClassLoader()); - this.state = state; - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - String file = name.replace('.', '/') + ".class"; - if (state.files().contains(file)) { - byte[] bytes = state.asBytes(file); - return defineClass(name, bytes, 0, bytes.length); - } - return super.findClass(name); - } - } } diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index 2f90dcb1158..7e2e25e8715 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -5,13 +5,16 @@ namespace modules { import java.util.* import jet.modules.* -class ModuleSetBuilder() { - val modules: ArrayList = ArrayList() +class ModuleSetBuilder(): IModuleSetBuilder { + val modules: ArrayList = ArrayList() fun module(name: String, callback: fun ModuleBuilder.()) { val builder = ModuleBuilder(name) builder.callback() + modules.add(builder) } + + override fun getModules(): List? = modules } class SourcesBuilder(val parent: ModuleBuilder) { @@ -46,6 +49,7 @@ class ModuleBuilder(val name: String): IModuleBuilder { override fun getSourceFiles(): List? = sourceFiles override fun getClasspathRoots(): List? = classpathRoots + override fun getModuleName(): String? = name } } \ No newline at end of file diff --git a/stdlib/src/jet/modules/IModuleBuilder.java b/stdlib/src/jet/modules/IModuleBuilder.java index 53ac51123c6..c845e04a021 100644 --- a/stdlib/src/jet/modules/IModuleBuilder.java +++ b/stdlib/src/jet/modules/IModuleBuilder.java @@ -6,6 +6,7 @@ import java.util.List; * @author yole */ public interface IModuleBuilder { + String getModuleName(); List getSourceFiles(); List getClasspathRoots(); } diff --git a/stdlib/src/jet/modules/IModuleSetBuilder.java b/stdlib/src/jet/modules/IModuleSetBuilder.java new file mode 100644 index 00000000000..7f5f03dc3d2 --- /dev/null +++ b/stdlib/src/jet/modules/IModuleSetBuilder.java @@ -0,0 +1,10 @@ +package jet.modules; + +import java.util.List; + +/** + * @author yole + */ +public interface IModuleSetBuilder { + List getModules(); +} From d643c72a09ef788f9d763146b3dcca89fc6bfea4 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 31 Oct 2011 17:31:02 +0300 Subject: [PATCH 22/31] Unnecessary dependency removed --- idea/idea.iml | 1 - 1 file changed, 1 deletion(-) diff --git a/idea/idea.iml b/idea/idea.iml index c994d198190..061858ad7f7 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -20,7 +20,6 @@ - From f82259ae84f2bd48b7fa4eb020c73aba014638e6 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 31 Oct 2011 17:40:05 +0300 Subject: [PATCH 23/31] Detailed session desc for CodeGen --- docs/CodeGen2012_Proposal.txt | 79 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/docs/CodeGen2012_Proposal.txt b/docs/CodeGen2012_Proposal.txt index 5189b15d3a5..95bfe306982 100644 --- a/docs/CodeGen2012_Proposal.txt +++ b/docs/CodeGen2012_Proposal.txt @@ -3,62 +3,73 @@ Code Generation 2012 - Session Proposal Form Submission Deadline: Friday December 9th 2011 Session title: -Creating DSLs in Kotlin + +DSLs in Kotlin Session type and duration: + Tutorial, 60 min Session abstract: -This should be a brief description of the session focusing on its content and objectives. You will need to cut and paste this text into a web form as part of the submission process. The session abstract will be used on the event web site to promote your session. -Kotlin is a statically typed programming language for the JVM proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. One can even mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin. +Kotlin is a statically typed programming language for the JVM proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. The language is fully Java compatible, so one can mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin. -In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes covering many interesting language features such as -* type inference, -* function literals (closures), -* operator overloading/overriding, -* extension functions -* and more… +In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes explanation of interesting language features illustrated with practical use-cases. -As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Along with this example we'll demonstrate LINQ-like collection processing and a DSL for program module definitions. +As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. This enables specifying declarative data right inside the code. Want to describe a build file? Xml/HTML? Swing UI? Use builders! Benefits of participating: -What will participants get out of taking part in the session? It is very important to think about this and describe it in your proposal. + +Participants will learn about Kotlin and how a few language features can be combined to create internal DSLs in a natural and flexible way. Process & timetable: -How will the session work? You might want to describe any exercises or group working. Consider providing a detailed timetable. Indicate the way in which the audience is involved. + +Introduction to Kotlin — 7-10 minutes +Q&A - 5 minutes +DSL-enabling features - 15 minutes +Q&A - 5 minutes +Builders (live demo) - 20 minutes +Q&A - 5 minutes Session outputs: -Indicate the form of any outputs (e.g. web page, poster at conference, blog posting etc) and their likely content (summary, actions points etc.) + +Slides, example code Intended Audience: -Note any required skills/knowledge/ experience. What job roles would this session be particularly applicable to. + +The session is intended for developers and tech. leads. +We expect the audience to be familiar with basic concepts of OOP and one of the statically typed languages (Java, Scala, C#, C++ etc) Availability: -Indicate if there are any constraints in your participation or whether it makes sense to run your session before or after another session you've proposed + +No constraints Detailed Description / Supporting Information + A fuller description of the session describing the content, rationale and describing any previous occasions on which the session has been run. +Kotlin is a new statically typed JVM-targeted programming language developed by JetBrains and intended for industrial use. Kotlin is designed to be fully Java compatible, and at the same time safer, more concise than Java and way simpler than its main competitor, Scala. Also, IDE support is being developed in parallel with the language itself. + +This session focuses on the language features that enable DSL creation and corresponding patterns. + +During the introduction, we will give an overview of the language. The features we’re planning to cover include: +* type inference; +* function literals (closures); +* extension functions; +* operator overloading/overriding; +* null safety and automatic casts. + +As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Builders are a flexible and clean way of describing declarative data in the code with very little syntactic overhead. The technique is so handy that Kotlin uses it instead of XML for compiler configuration, which we will show in action along with XML/HTML and Swing UI building. +This part is presented as a live demo within the IntelliJ IDEA IDE for Kotlin. Along with this example we'll demonstrate a DSL for LINQ-like collection processing. + +This session has not been run before, but the material we use is partly taken from Kotlin talks from OSCON, StrangeLoop and Devoxx. + + Main presenter name, contact details and biography -Name: -Affiliation: -Telephone / Skype: -Email: +Name: Andrey Breslav +Affiliation: JetBrains +Telephone / Skype: andrey.breslav @ skype +Email: andrey.breslav@jetbrains.com Biography (up to 100 words): - -Additional Presenter(s) (if any) -Name: -Affiliation: -Telephone / Skype: -Email: -Biography (up to 100 words): - -Name: -Affiliation: -Telephone / Skype: -Email: -Biography (up to 100 words): - - +Andrey is the lead language designer working on Project Kotlin. He joined JetBrains in 2010. \ No newline at end of file From 5a9c50d3742760ec4452c83f8b1ec7ad4fc612e9 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Mon, 31 Oct 2011 19:26:27 +0300 Subject: [PATCH 24/31] PSI is just a tree with getters in Kotlin --- .../org/jetbrains/jet/lang/psi/JetClass.java | 12 ------------ .../run/JetRunConfigurationProducer.java | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java index 0b1b54b0509..dc232e66306 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -105,17 +104,6 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj return body.getProperties(); } - public String getFQName() { - JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(this, JetNamespace.class, JetClass.class); - if (parent instanceof JetNamespace) { - return ((JetNamespace) parent).getFQName() + "." + getName(); - } - if (parent instanceof JetClass) { - return ((JetClass) parent).getFQName() + "." + getName(); - } - return getName(); - } - public boolean isTrait() { return findChildByType(JetTokens.TRAIT_KEYWORD) != null; } diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java index 439124e4b46..b99895b0542 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java @@ -8,7 +8,11 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import org.jetbrains.jet.lang.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetNamedDeclaration; +import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.plugin.JetMainDetector; /** @@ -21,6 +25,17 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im super(JetRunConfigurationType.getInstance()); } + private static String getFQName(JetClass jetClass) { + JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(jetClass, JetNamespace.class, JetClass.class); + if (parent instanceof JetNamespace) { + return ((JetNamespace) parent).getFQName() + "." + jetClass.getName(); + } + if (parent instanceof JetClass) { + return getFQName(((JetClass) parent)) + "." + jetClass.getName(); + } + return jetClass.getName(); + } + @Override public PsiElement getSourceElement() { return mySourceElement; @@ -31,7 +46,7 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im JetClass containingClass = (JetClass) location.getParentElement(JetClass.class); if (containingClass != null && JetMainDetector.hasMain(containingClass.getDeclarations())) { mySourceElement = containingClass; - return createConfigurationByQName(location.getModule(), configurationContext, containingClass.getFQName()); + return createConfigurationByQName(location.getModule(), configurationContext, getFQName(containingClass)); } PsiFile psiFile = location.getPsiElement().getContainingFile(); if (psiFile instanceof JetFile) { From 2bf5ac5037c81de0b9da70aa6d75173d01585a6a Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Nov 2011 12:36:35 +0300 Subject: [PATCH 25/31] Final version of the proposal --- docs/CodeGen2012_Proposal.txt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/CodeGen2012_Proposal.txt b/docs/CodeGen2012_Proposal.txt index 95bfe306982..879d74bd7b3 100644 --- a/docs/CodeGen2012_Proposal.txt +++ b/docs/CodeGen2012_Proposal.txt @@ -12,11 +12,11 @@ Tutorial, 60 min Session abstract: -Kotlin is a statically typed programming language for the JVM proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. The language is fully Java compatible, so one can mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin. +Kotlin is a statically typed programming language for the JVM, proposed recently by JetBrains. The language is intended for industrial use as a safer and more convenient alternative to Java. The language is fully Java compatible, so one can mix Kotlin and Java sources in the same project. Language documentation is available at http://jetbrains.com/kotlin. In this session we will demonstrate Kotlin's abilities to define APIs as domain-specific languages (DSLs). This includes explanation of interesting language features illustrated with practical use-cases. -As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. This enables specifying declarative data right inside the code. Want to describe a build file? Xml/HTML? Swing UI? Use builders! +As a flagship example we will present Type-safe Builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. This enables specifying declarative data right inside the code. Want to describe a build file? Xml/HTML? Swing UI? Use builders! We will show how Kotlin compiler itself uses builders to specify modules. Along with this example we will show and explain a few other DSLs built in Kotlin. Benefits of participating: @@ -37,8 +37,8 @@ Slides, example code Intended Audience: -The session is intended for developers and tech. leads. -We expect the audience to be familiar with basic concepts of OOP and one of the statically typed languages (Java, Scala, C#, C++ etc) +The session is intended for developers and tech leads. +We expect the audience to be familiar with basic concepts of OOP and some of the statically typed languages (Java, Scala, C#, C++ etc). Availability: @@ -46,25 +46,22 @@ No constraints Detailed Description / Supporting Information -A fuller description of the session describing the content, rationale and describing any previous occasions on which the session has been run. - Kotlin is a new statically typed JVM-targeted programming language developed by JetBrains and intended for industrial use. Kotlin is designed to be fully Java compatible, and at the same time safer, more concise than Java and way simpler than its main competitor, Scala. Also, IDE support is being developed in parallel with the language itself. This session focuses on the language features that enable DSL creation and corresponding patterns. During the introduction, we will give an overview of the language. The features we’re planning to cover include: -* type inference; * function literals (closures); * extension functions; +* type inference; * operator overloading/overriding; * null safety and automatic casts. As a flagship example we will present type-safe builders, a technique that improves upon Groovy builders (http://groovy.codehaus.org/Builders) by making them statically checked for correctness. Builders are a flexible and clean way of describing declarative data in the code with very little syntactic overhead. The technique is so handy that Kotlin uses it instead of XML for compiler configuration, which we will show in action along with XML/HTML and Swing UI building. -This part is presented as a live demo within the IntelliJ IDEA IDE for Kotlin. Along with this example we'll demonstrate a DSL for LINQ-like collection processing. +This part is presented as a live demo within the IntelliJ IDEA IDE for Kotlin. Along with this example we'll demonstrate a DSL for LINQ-like collection processing and how to turn any type into a Fluent interface (http://martinfowler.com/bliki/FluentInterface.html) with extension functions. This session has not been run before, but the material we use is partly taken from Kotlin talks from OSCON, StrangeLoop and Devoxx. - Main presenter name, contact details and biography Name: Andrey Breslav From 43faa7747805c8b5fc88bbc54c6af336561e1357 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Nov 2011 12:49:20 +0300 Subject: [PATCH 26/31] Standard library is imported properly rather than enclosing the user code --- .../src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java | 4 +++- .../jetbrains/jet/plugin/JetQuickDocumentationProvider.java | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index ade95c7d747..70e6a3be7f9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -68,8 +68,10 @@ public class AnalyzingUtils { JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); ModuleDescriptor owner = new ModuleDescriptor(""); - final WritableScope scope = new WritableScopeImpl(libraryScope, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); +// final WritableScope scope = new WritableScopeImpl(libraryScope, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); + final WritableScope scope = new WritableScopeImpl(JetScope.EMPTY, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope); + scope.importScope(libraryScope); TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) { @Override diff --git a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java index 6108b7e0006..43ca6abd27f 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java @@ -8,7 +8,6 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.resolve.DescriptorRenderer; From d07314a8b500fd9eea8a7e74c3b013ace9b6159f Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 1 Nov 2011 10:56:24 +0100 Subject: [PATCH 27/31] KT-416 --- .../jet/codegen/ExpressionCodegen.java | 55 ++++++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 29 ++++++++++ .../jet/codegen/intrinsics/BinaryOp.java | 9 +++ .../testData/codegen/regressions/kt416.jet | 4 ++ .../jet/codegen/ControlStructuresTest.java | 5 ++ 5 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/codegen/regressions/kt416.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a76f5e3d782..c0fd4c8b2e2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1238,29 +1238,44 @@ public class ExpressionCodegen extends JetVisitor { @Override public StackValue visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, StackValue receiver) { - genToJVMStack(expression.getReceiverExpression()); - Label ifnull = new Label(); - Label end = new Label(); - v.dup(); - v.ifnull(ifnull); - JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()); - StackValue propValue = genQualified(StackValue.onStack(typeMapper.mapType(receiverType)), expression.getSelectorExpression()); - Type type = propValue.type; - propValue.put(type, v); - if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) { - StackValue.valueOf(v, type); - type = JetTypeMapper.boxType(type); - } - v.goTo(end); + JetExpression expr = expression.getReceiverExpression(); + JetType receiverJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()); + Type receiverType = typeMapper.mapType(receiverJetType); + gen(expr, receiverType); + if(receiverType.getSort() != Type.OBJECT && receiverType.getSort() != Type.ARRAY) { + StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression()); + Type type = propValue.type; + propValue.put(type, v); + if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) { + StackValue.valueOf(v, type); + type = JetTypeMapper.boxType(type); + } - v.mark(ifnull); - v.pop(); - if(!propValue.type.equals(Type.VOID_TYPE)) { - v.aconst(null); + return StackValue.onStack(type); } - v.mark(end); + else { + Label ifnull = new Label(); + Label end = new Label(); + v.dup(); + v.ifnull(ifnull); + StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression()); + Type type = propValue.type; + propValue.put(type, v); + if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) { + StackValue.valueOf(v, type); + type = JetTypeMapper.boxType(type); + } + v.goTo(end); - return StackValue.onStack(type); + v.mark(ifnull); + v.pop(); + if(!propValue.type.equals(Type.VOID_TYPE)) { + v.aconst(null); + } + v.mark(end); + + return StackValue.onStack(type); + } } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 947cf407491..e0a184f7676 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -15,6 +15,7 @@ import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.resolve.DescriptorRenderer; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; import java.util.*; @@ -415,6 +416,34 @@ public class JetTypeMapper { throw new UnsupportedOperationException("Unknown type " + jetType); } + public static Type unboxType(final Type type) { + if (type == JL_INTEGER_TYPE) { + return Type.INT_TYPE; + } + else if (type == JL_BOOLEAN_TYPE) { + return Type.BOOLEAN_TYPE; + } + else if (type == JL_CHAR_TYPE) { + return Type.CHAR_TYPE; + } + else if (type == JL_SHORT_TYPE) { + return Type.SHORT_TYPE; + } + else if (type == JL_LONG_TYPE) { + return Type.LONG_TYPE; + } + else if (type == JL_BYTE_TYPE) { + return Type.BYTE_TYPE; + } + else if (type == JL_FLOAT_TYPE) { + return Type.FLOAT_TYPE; + } + else if (type == JL_DOUBLE_TYPE) { + return Type.DOUBLE_TYPE; + } + throw new UnsupportedOperationException("Unboxing: " + type); + } + public static Type boxType(Type asmType) { switch (asmType.getSort()) { case Type.VOID: diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java index a34e333845c..e813857f0de 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/BinaryOp.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics; import com.intellij.psi.PsiElement; import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; import org.objectweb.asm.Type; @@ -21,6 +22,10 @@ public class BinaryOp implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { + boolean nullable = expectedType.getSort() == Type.OBJECT; + if(nullable) { + expectedType = JetTypeMapper.unboxType(expectedType); + } if (arguments.size() == 1) { // intrinsic is called as an ordinary function if (receiver != null) { @@ -33,6 +38,10 @@ public class BinaryOp implements IntrinsicMethod { codegen.gen(arguments.get(1), expectedType); } v.visitInsn(expectedType.getOpcode(opcode)); + + if(nullable) { + StackValue.onStack(expectedType).put(expectedType = JetTypeMapper.boxType(expectedType), v); + } return StackValue.onStack(expectedType); } } diff --git a/compiler/testData/codegen/regressions/kt416.jet b/compiler/testData/codegen/regressions/kt416.jet new file mode 100644 index 00000000000..a2108a6b9fb --- /dev/null +++ b/compiler/testData/codegen/regressions/kt416.jet @@ -0,0 +1,4 @@ +fun box() : String { + var a = 10 + return if(a?.plus(10) == 20) "OK" else "fail" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index f6da4b65c87..d3748a7b737 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -207,4 +207,9 @@ public class ControlStructuresTest extends CodegenTestCase { public void testKt299() throws Exception { blackBoxFile("regressions/kt299.jet"); } + + public void testKt416() throws Exception { + blackBoxFile("regressions/kt416.jet"); + System.out.println(generateToText()); + } } From 3588779f1945fca7478458efa90ceccb93df7340 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Nov 2011 16:04:55 +0300 Subject: [PATCH 28/31] When a file is changed in the IDE, we do not recheck function bodies and other executable code in other files: only declarations to povide resolution context for the changed file --- .../org/jetbrains/jet/cli/CompileSession.java | 3 +- .../jet/lang/resolve/java/AnalyzerFacade.java | 3 + .../jet/lang/resolve/AnalyzingUtils.java | 16 +++-- .../jet/lang/resolve/BodyResolver.java | 63 ++++++++++--------- .../jet/lang/resolve/ControlFlowAnalyzer.java | 2 + .../jet/lang/resolve/DeclarationsChecker.java | 7 ++- .../lang/resolve/TopDownAnalysisContext.java | 39 +++++++++++- .../jet/lang/resolve/TopDownAnalyzer.java | 21 +++++-- .../lang/resolve/TypeHierarchyResolver.java | 2 +- .../jet/plugin/compiler/JetCompiler.java | 6 +- 10 files changed, 117 insertions(+), 45 deletions(-) diff --git a/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java index 90807c39b91..120a431fe08 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.cli; +import com.google.common.base.Predicates; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; @@ -82,7 +83,7 @@ public class CompileSession { final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS); List allNamespaces = new ArrayList(mySourceFileNamespaces); allNamespaces.addAll(myLibrarySourceFileNamespaces); - myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, JetControlFlowDataTraceFactory.EMPTY); + myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY); ErrorCollector errorCollector = new ErrorCollector(myBindingContext); errorCollector.report(); return !errorCollector.hasErrors; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java index b14585f1d4d..826e741d31a 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacade.java @@ -1,7 +1,9 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.base.Predicates; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiFile; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; @@ -58,6 +60,7 @@ public class AnalyzerFacade { BindingContext bindingContext = analyzingUtils.analyzeNamespaces( file.getProject(), declarationProvider.fun(file), + Predicates.equalTo(file), JetControlFlowDataTraceFactory.EMPTY); return new Result(bindingContext, PsiModificationTracker.MODIFICATION_COUNT); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 70e6a3be7f9..753b8709857 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -1,9 +1,12 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; @@ -59,19 +62,24 @@ public class AnalyzingUtils { Project project = namespace.getProject(); List declarations = Collections.singletonList(namespace); - return analyzeNamespaces(project, declarations, flowDataTraceFactory); + return analyzeNamespaces(project, declarations, Predicates.equalTo(namespace.getContainingFile()), flowDataTraceFactory); } - public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull Collection declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { + public BindingContext analyzeNamespaces( + @NotNull Project project, + @NotNull Collection declarations, + @NotNull Predicate filesToAnalyzeCompletely, + @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); ModuleDescriptor owner = new ModuleDescriptor(""); -// final WritableScope scope = new WritableScopeImpl(libraryScope, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); + final WritableScope scope = new WritableScopeImpl(JetScope.EMPTY, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace"); importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope); scope.importScope(libraryScope); + TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) { @Override @@ -103,7 +111,7 @@ public class AnalyzingUtils { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { throw new IllegalStateException("Must be guaranteed not to happen by the parser"); } - }, declarations, flowDataTraceFactory); + }, declarations, filesToAnalyzeCompletely, flowDataTraceFactory); return bindingTraceContext.getBindingContext(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 7bc2afd02c8..b0c86e3a500 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -71,7 +71,6 @@ public class BodyResolver { } - public void resolveBehaviorDeclarationBodies() { resolveDelegationSpecifierLists(); @@ -86,34 +85,6 @@ public class BodyResolver { computeDeferredTypes(); } - private void computeDeferredTypes() { - Collection deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY); - if (deferredTypes != null) { - final Queue queue = new Queue(deferredTypes.size()); - context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler() { - @Override - public void handleRecord(WritableSlice deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) { - queue.addLast(value); - } - }); - for (DeferredType deferredType : deferredTypes) { - queue.addLast(deferredType); - } - while (!queue.isEmpty()) { - DeferredType deferredType = queue.pullFirst(); - if (!deferredType.isComputed()) { - try { - deferredType.getActualType(); // to compute - } - catch (ReenteringLazyValueComputationException e) { - // A problem should be reported while computing the type - } - } - } - } - } - - private void resolveDelegationSpecifierLists() { // TODO : Make sure the same thing is not initialized twice for (Map.Entry entry : context.getClasses().entrySet()) { @@ -125,6 +96,7 @@ public class BodyResolver { } private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { + if (!context.completeAnalysisNeeded(jetClass)) return; final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final JetScope scopeForConstructor = primaryConstructor == null ? null @@ -278,7 +250,6 @@ public class BodyResolver { } private void resolveClassAnnotations() { - } private void resolveAnonymousInitializers() { @@ -291,6 +262,7 @@ public class BodyResolver { } private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { + if (!context.completeAnalysisNeeded(jetClassOrObject)) return; List anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); if (jetClassOrObject.hasPrimaryConstructor()) { ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); @@ -320,6 +292,7 @@ public class BodyResolver { } private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { + if (!context.completeAnalysisNeeded(declaration)) return; final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo @@ -419,6 +392,7 @@ public class BodyResolver { Set processed = Sets.newHashSet(); for (Map.Entry entry : context.getClasses().entrySet()) { JetClass jetClass = entry.getKey(); + if (!context.completeAnalysisNeeded(jetClass)) continue; MutableClassDescriptor classDescriptor = entry.getValue(); for (JetProperty property : jetClass.getProperties()) { @@ -444,6 +418,7 @@ public class BodyResolver { // Top-level properties & properties of objects for (Map.Entry entry : this.context.getProperties().entrySet()) { JetProperty property = entry.getKey(); + if (!context.completeAnalysisNeeded(property)) return; if (processed.contains(property)) continue; final PropertyDescriptor propertyDescriptor = entry.getValue(); @@ -556,6 +531,7 @@ public class BodyResolver { @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, @NotNull JetScope declaringScope) { + if (!context.completeAnalysisNeeded(function)) return; JetExpression bodyExpression = function.getBodyExpression(); if (bodyExpression != null) { @@ -580,4 +556,31 @@ public class BodyResolver { assert functionDescriptor.getReturnType() != null; } + + private void computeDeferredTypes() { + Collection deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY); + if (deferredTypes != null) { + final Queue queue = new Queue(deferredTypes.size()); + context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler() { + @Override + public void handleRecord(WritableSlice deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) { + queue.addLast(value); + } + }); + for (DeferredType deferredType : deferredTypes) { + queue.addLast(deferredType); + } + while (!queue.isEmpty()) { + DeferredType deferredType = queue.pullFirst(); + if (!deferredType.isComputed()) { + try { + deferredType.getActualType(); // to compute + } + catch (ReenteringLazyValueComputationException e) { + // A problem should be reported while computing the type + } + } + } + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index fbea9ad37d4..2efa0842a4b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -42,6 +42,8 @@ public class ControlFlowAnalyzer { JetNamedFunction function = entry.getKey(); FunctionDescriptorImpl functionDescriptor = entry.getValue(); + if (!context.completeAnalysisNeeded(function)) continue; + final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index acebd21b8e6..8a7beb5a7f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -40,7 +40,8 @@ public class DeclarationsChecker { for (Map.Entry entry : classes.entrySet()) { JetClass aClass = entry.getKey(); MutableClassDescriptor classDescriptor = entry.getValue(); - + if (!context.completeAnalysisNeeded(aClass)) continue; + checkClass(aClass, classDescriptor); checkModifiers(aClass.getModifierList()); } @@ -50,6 +51,7 @@ public class DeclarationsChecker { JetObjectDeclaration objectDeclaration = entry.getKey(); MutableClassDescriptor objectDescriptor = entry.getValue(); + if (!context.completeAnalysisNeeded(objectDeclaration)) continue; checkObject(objectDeclaration, objectDescriptor); } @@ -58,6 +60,7 @@ public class DeclarationsChecker { JetNamedFunction function = entry.getKey(); FunctionDescriptorImpl functionDescriptor = entry.getValue(); + if (!context.completeAnalysisNeeded(function)) continue; checkFunction(function, functionDescriptor); checkModifiers(function.getModifierList()); } @@ -67,6 +70,7 @@ public class DeclarationsChecker { JetProperty property = entry.getKey(); PropertyDescriptor propertyDescriptor = entry.getValue(); + if (!context.completeAnalysisNeeded(property)) continue; checkProperty(property, propertyDescriptor); checkModifiers(property.getModifierList()); } @@ -77,6 +81,7 @@ public class DeclarationsChecker { for (Map.Entry entry : context.getClasses().entrySet()) { MutableClassDescriptor classDescriptor = entry.getValue(); JetClass jetClass = entry.getKey(); + if (!context.completeAnalysisNeeded(jetClass)) return; if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) { for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java index 2acc11bc2c9..1fd0bad84f5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java @@ -1,13 +1,18 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.base.Predicate; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import java.io.PrintStream; import java.util.Map; import java.util.Set; @@ -32,10 +37,42 @@ import java.util.Set; private final Map properties = Maps.newLinkedHashMap(); private final Set primaryConstructorParameterProperties = Sets.newHashSet(); - public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace) { + private final Predicate analyzeCompletely; + + private StringBuilder debugOutput; + + public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate analyzeCompletely) { this.trace = new ObservableBindingTrace(trace); this.semanticServices = semanticServices; this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); + this.analyzeCompletely = analyzeCompletely; + } + + public void debug(Object message) { + if (debugOutput != null) { + debugOutput.append(message).append("\n"); + } + } + + /*package*/ void enableDebugOutput() { + if (debugOutput == null) { + debugOutput = new StringBuilder(); + } + } + + /*package*/ void printDebugOutput(PrintStream out) { + if (debugOutput != null) { + out.print(debugOutput); + } + } + + public boolean completeAnalysisNeeded(@NotNull PsiElement element) { + PsiFile containingFile = element.getContainingFile(); + boolean result = containingFile != null && analyzeCompletely.apply(containingFile); + if (!result) { + debug(containingFile); + } + return result; } public ObservableBindingTrace getTrace() { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index e0cf26bce1b..f4cc0d05f89 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -1,5 +1,8 @@ package org.jetbrains.jet.lang.resolve; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; @@ -25,21 +28,25 @@ public class TopDownAnalyzer { @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, @NotNull JetScope outerScope, - NamespaceLike owner, + @NotNull NamespaceLike owner, @NotNull Collection declarations, + @NotNull Predicate analyzeCompletely, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { - process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false); + process(semanticServices, trace, outerScope, owner, declarations, analyzeCompletely, flowDataTraceFactory, false); } private static void process( @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, @NotNull JetScope outerScope, - NamespaceLike owner, + @NotNull NamespaceLike owner, @NotNull Collection declarations, + @NotNull Predicate analyzeCompletely, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, boolean declaredLocally) { - TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); + TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely); +// context.enableDebugOutput(); + new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); new DelegationResolver(context).process(); @@ -47,13 +54,15 @@ public class TopDownAnalyzer { new BodyResolver(context).resolveBehaviorDeclarationBodies(); new DeclarationsChecker(context).process(); new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); + + context.printDebugOutput(System.out); } public static void processStandardLibraryNamespace( @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, @NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) { - TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); + TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.alwaysTrue()); context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope()); context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace); context.getDeclaringScopes().put(namespace, outerScope); @@ -107,7 +116,7 @@ public class TopDownAnalyzer { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { return ClassObjectStatus.NOT_ALLOWED; } - }, Collections.singletonList(object), JetControlFlowDataTraceFactory.EMPTY, true); + }, Collections.singletonList(object), Predicates.equalTo(object.getContainingFile()), JetControlFlowDataTraceFactory.EMPTY, true); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 0b7dc1377a1..147a2eddee6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -36,7 +36,7 @@ public class TypeHierarchyResolver { this.context = context; } - public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull Collection declarations) { + public void process(@NotNull JetScope outerScope, @NotNull NamespaceLike owner, @NotNull Collection declarations) { collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes processTypeImports(); diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index 0b6854b3770..7327491ec3c 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.plugin.compiler; +import com.google.common.base.Predicates; import com.google.common.collect.Lists; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompileContext; @@ -77,7 +78,10 @@ public class JetCompiler implements TranslatingCompiler { } } - BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(compileContext.getProject(), namespaces, JetControlFlowDataTraceFactory.EMPTY); + BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces( + compileContext.getProject(), namespaces, + Predicates.alwaysTrue(), + JetControlFlowDataTraceFactory.EMPTY); boolean errors = false; for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { From 496bdc287942aea2d0b2bcb8ce8a69da972c1aca Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Nov 2011 16:37:54 +0300 Subject: [PATCH 29/31] Debug output --- .../src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index f4cc0d05f89..da0964d2f17 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -46,6 +46,7 @@ public class TopDownAnalyzer { boolean declaredLocally) { TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely); // context.enableDebugOutput(); + context.debug("Enter"); new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); @@ -54,7 +55,8 @@ public class TopDownAnalyzer { new BodyResolver(context).resolveBehaviorDeclarationBodies(); new DeclarationsChecker(context).process(); new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); - + + context.debug("Exit"); context.printDebugOutput(System.out); } From 739417dc9d6a76d6102b1763104a662e693b75ee Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 1 Nov 2011 17:40:43 +0300 Subject: [PATCH 30/31] KT-389 Wrong type inference for varargs etc. --- .../jetbrains/jet/codegen/JetTypeMapper.java | 4 +- .../resolve/java/JavaDescriptorResolver.java | 15 ++++++- .../descriptors/FunctionDescriptorUtil.java | 34 ++------------- .../descriptors/ValueParameterDescriptor.java | 4 +- .../ValueParameterDescriptorImpl.java | 19 +++++---- .../lang/resolve/ClassDescriptorResolver.java | 41 +++++++++++++++++-- .../jet/lang/resolve/calls/CallResolver.java | 14 ++++++- .../ValueArgumentsToParametersMapper.java | 8 ++-- .../jetbrains/jet/lang/types/ErrorUtils.java | 2 +- .../jet/lang/types/JetStandardClasses.java | 2 +- .../jet/lang/types/JetStandardLibrary.java | 4 +- .../ClosureExpressionsTypingVisitor.java | 2 +- .../jet/resolve/DescriptorRenderer.java | 2 +- .../full/VarargTypes.jet | 26 ++++++++++++ 14 files changed, 118 insertions(+), 59 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 947cf407491..46d588a839f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -462,7 +462,7 @@ public class JetTypeMapper { } for (ValueParameterDescriptor parameter : parameters) { Type type = mapType(parameter.getOutType()); - if(parameter.isVararg()) { + if(parameter.getVarargElementType() != null) { type = Type.getType("[" + type.getDescriptor()); } valueParameterTypes.add(type); @@ -562,7 +562,7 @@ public class JetTypeMapper { parameterTypes.add(mapType(receiver.getType())); } for (ValueParameterDescriptor parameter : parameters) { - if(parameter.isVararg()) { + if(parameter.getVarargElementType() != null) { Type type = mapType(parameter.getOutType()); type = Type.getType("[" + type.getDescriptor()); parameterTypes.add(type); 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 67bb062e71e..a66b089f62c 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 @@ -300,15 +300,26 @@ public class JavaDescriptorResolver { for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { PsiParameter parameter = parameters[i]; String name = parameter.getName(); + PsiType psiType = parameter.getType(); + + JetType varargElementType; + if (psiType instanceof PsiEllipsisType) { + PsiEllipsisType psiEllipsisType = (PsiEllipsisType) psiType; + varargElementType = semanticServices.getTypeTransformer().transformToType(psiEllipsisType.getComponentType()); + } + else { + varargElementType = null; + } + JetType outType = semanticServices.getTypeTransformer().transformToType(psiType); result.add(new ValueParameterDescriptorImpl( containingDeclaration, i, Collections.emptyList(), // TODO name == null ? "p" + i : name, null, // TODO : review - semanticServices.getTypeTransformer().transformToType(parameter.getType()), + outType, false, - parameter.isVarArgs() + varargElementType )); } return result; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 3990e09e9a7..cb193b40b69 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -16,35 +16,6 @@ import java.util.*; * @author abreslav */ public class FunctionDescriptorUtil { - /** @return Minimal number of arguments to be passed */ - public static int getMinimumArity(@NotNull FunctionDescriptor functionDescriptor) { - int result = 0; - for (ValueParameterDescriptor valueParameter : functionDescriptor.getValueParameters()) { - if (valueParameter.hasDefaultValue()) { - break; - } - result++; - } - return result; - } - - /** - * @return Maximum number of arguments that can be passed. -1 if unbound (vararg) - */ - public static int getMaximumArity(@NotNull FunctionDescriptor functionDescriptor) { - List unsubstitutedValueParameters = functionDescriptor.getValueParameters(); - if (unsubstitutedValueParameters.isEmpty()) { - return 0; - } - // TODO : check somewhere that vararg is only the last one, and that varargs do not have default values - - ValueParameterDescriptor lastParameter = unsubstitutedValueParameters.get(unsubstitutedValueParameters.size() - 1); - if (lastParameter.isVararg()) { - return -1; - } - return unsubstitutedValueParameters.size(); - } - public static Map createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List typeArguments) { if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap(); @@ -69,13 +40,16 @@ public class FunctionDescriptorUtil { ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i); // TODO : Lazy? JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getOutType(), Variance.IN_VARIANCE); + JetType varargElementType = unsubstitutedValueParameter.getVarargElementType(); + JetType substituteVarargElementType = varargElementType == null ? null : substitutor.substitute(varargElementType, Variance.IN_VARIANCE); if (substitutedType == null) return null; result.add(new ValueParameterDescriptorImpl( substitutedDescriptor, unsubstitutedValueParameter, unsubstitutedValueParameter.getAnnotations(), unsubstitutedValueParameter.getInType() == null ? null : substitutedType, - substitutedType + substitutedType, + substituteVarargElementType )); } return result; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java index ba7131b36c0..0cbe2362042 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.descriptors; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.JetType; /** @@ -15,7 +16,7 @@ public interface ValueParameterDescriptor extends VariableDescriptor { int getIndex(); boolean hasDefaultValue(); boolean isRef(); - boolean isVararg(); + @Nullable JetType getVarargElementType(); @Override @NotNull @@ -26,4 +27,5 @@ public interface ValueParameterDescriptor extends VariableDescriptor { @NotNull ValueParameterDescriptor copy(DeclarationDescriptor newOwner); + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java index 8b13a526dc7..b56cf9f7ea9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java @@ -14,7 +14,7 @@ import java.util.List; */ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor { private final boolean hasDefaultValue; - private final boolean isVararg; + private final JetType varargElementType; private final boolean isVar; private final int index; private final ValueParameterDescriptor original; @@ -27,12 +27,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @Nullable JetType inType, @NotNull JetType outType, boolean hasDefaultValue, - boolean isVararg) { + @Nullable JetType varargElementType) { super(containingDeclaration, annotations, name, inType, outType); this.original = this; this.index = index; this.hasDefaultValue = hasDefaultValue; - this.isVararg = isVararg; + this.varargElementType = varargElementType; this.isVar = inType != null; } @@ -41,13 +41,14 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull ValueParameterDescriptor original, @NotNull List annotations, @Nullable JetType inType, - @NotNull JetType outType + @NotNull JetType outType, + @Nullable JetType varargElementType ) { super(containingDeclaration, annotations, original.getName(), inType, outType); this.original = original; this.index = original.getIndex(); this.hasDefaultValue = original.hasDefaultValue(); - this.isVararg = original.isVararg(); + this.varargElementType = varargElementType; this.isVar = inType != null; } @@ -76,9 +77,9 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme throw new UnsupportedOperationException(); // TODO } - @Override - public boolean isVararg() { - return isVararg; + @Nullable + public JetType getVarargElementType() { + return varargElementType; } @NotNull @@ -106,6 +107,6 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull @Override public ValueParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) { - return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, isVararg); + return new ValueParameterDescriptorImpl(newOwner, index, Lists.newArrayList(getAnnotations()), getName(), getInType(), getOutType(), hasDefaultValue, varargElementType); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 4f7bf2ececf..112c798ab46 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -246,21 +246,56 @@ public class ClassDescriptorResolver { @NotNull public MutableValueParameterDescriptor resolveValueParameterDescriptor(DeclarationDescriptor declarationDescriptor, JetParameter valueParameter, int index, JetType type) { + JetType varargElementType = null; + JetType variableType = type; + if (valueParameter.hasModifier(JetTokens.VARARG_KEYWORD)) { + varargElementType = type; + variableType = getVarargParameterType(type); + } MutableValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl( declarationDescriptor, index, annotationResolver.createAnnotationStubs(valueParameter.getModifierList()), JetPsiUtil.safeName(valueParameter.getName()), - valueParameter.isMutable() ? type : null, - type, + valueParameter.isMutable() ? variableType : null, + variableType, valueParameter.getDefaultValue() != null, - valueParameter.hasModifier(JetTokens.VARARG_KEYWORD) + varargElementType ); trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor); return valueParameterDescriptor; } + private JetType getVarargParameterType(JetType type) { + JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary(); + if (type.equals(standardLibrary.getByteType())) { + return standardLibrary.getByteArrayType(); + } + if (type.equals(standardLibrary.getCharType())) { + return standardLibrary.getCharArrayType(); + } + if (type.equals(standardLibrary.getShortType())) { + return standardLibrary.getShortArrayType(); + } + if (type.equals(standardLibrary.getIntType())) { + return standardLibrary.getIntArrayType(); + } + if (type.equals(standardLibrary.getLongType())) { + return standardLibrary.getLongArrayType(); + } + if (type.equals(standardLibrary.getFloatType())) { + return standardLibrary.getFloatArrayType(); + } + if (type.equals(standardLibrary.getDoubleType())) { + return standardLibrary.getDoubleArrayType(); + } + if (type.equals(standardLibrary.getBooleanType())) { + return standardLibrary.getBooleanArrayType(); + } + return standardLibrary.getArrayType(type); + } + public List resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List typeParameters) { List result = new ArrayList(); for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) { 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 976d5b9c070..5b93320fe05 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 @@ -387,13 +387,15 @@ public class CallResolver { ResolvedValueArgument valueArgument = entry.getValue(); ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); + JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor); + for (JetExpression expression : valueArgument.getArgumentExpressions()) { // JetExpression expression = valueArgument.getArgumentExpression(); // TODO : more attempts, with different expected types ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace); JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); if (type != null) { - constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); + constraintSystem.addSubtypingConstraint(type, effectiveExpectedType); } else { candidateCall.argumentHasNoType(); @@ -512,6 +514,14 @@ public class CallResolver { return results; } + private JetType getEffectiveExpectedType(ValueParameterDescriptor valueParameterDescriptor) { + JetType effectiveExpectedType = valueParameterDescriptor.getVarargElementType(); + if (effectiveExpectedType == null) { + effectiveExpectedType = valueParameterDescriptor.getOutType(); + } + return effectiveExpectedType; + } + private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { if (receiver instanceof AutoCastReceiver) { AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; @@ -606,7 +616,7 @@ public class CallResolver { ValueParameterDescriptor parameterDescriptor = entry.getKey(); ResolvedValueArgument resolvedArgument = entry.getValue(); - JetType parameterType = parameterDescriptor.getOutType(); + JetType parameterType = getEffectiveExpectedType(parameterDescriptor); List argumentExpressions = resolvedArgument.getArgumentExpressions(); for (JetExpression argumentExpression : argumentExpressions) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java index 402b3f1aa62..040a218e534 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ValueArgumentsToParametersMapper.java @@ -84,7 +84,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } else if (!valueParameters.isEmpty()) { ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { put(candidateCall, valueParameterDescriptor, valueArgument, varargs); usedParameters.add(valueParameterDescriptor); } @@ -123,7 +123,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { // temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list"); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); error = true; @@ -154,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; if (valueParameter.hasDefaultValue()) { candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT); } - else if (valueParameter.isVararg()) { + else if (valueParameter.getVarargElementType() != null) { candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); } else { @@ -182,7 +182,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; } private static void put(ResolvedCallImpl candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map varargs) { - if (valueParameterDescriptor.isVararg()) { + if (valueParameterDescriptor.getVarargElementType() != null) { VarargValueArgument vararg = varargs.get(valueParameterDescriptor); if (vararg == null) { vararg = new VarargValueArgument(); 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 52af4480db1..522a1b0d156 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -147,7 +147,7 @@ public class ErrorUtils { ERROR_PARAMETER_TYPE, ERROR_PARAMETER_TYPE, false, - false)); + null)); } return result; } 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 70db11221a4..e637d05de72 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -378,7 +378,7 @@ public class JetStandardClasses { List valueParameters = Lists.newArrayList(); for (int i = first; i <= last; i++) { JetType parameterType = arguments.get(i).getType(); - ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.emptyList(), "p" + i, null, parameterType, false, false); + ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.emptyList(), "p" + i, null, parameterType, false, null); valueParameters.add(valueParameterDescriptor); } return valueParameters; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 6029d19c358..7b35d6f582e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -316,8 +316,8 @@ public class JetStandardLibrary { } @NotNull - public JetType getArrayType(@NotNull Variance variance, @NotNull JetType argument) { - List types = Collections.singletonList(new TypeProjection(variance, argument)); + public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) { + List types = Collections.singletonList(new TypeProjection(projectionType, argument)); return new JetTypeImpl( Collections.emptyList(), getArray().getTypeConstructor(), diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java index e0b992f735e..a8c2fde4a6c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java @@ -87,7 +87,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) { ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); ValueParameterDescriptor it = new ValueParameterDescriptorImpl( - functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg() + functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType() ); valueParameterDescriptors.add(it); parameterTypes.add(it.getOutType()); diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index 2a52a1d3f54..a9bddbb2c7a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -133,7 +133,7 @@ public class DescriptorRenderer implements Renderer { @Override public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { builder.append(renderKeyword("value-parameter")).append(" "); - if (descriptor.isVararg()) { + if (descriptor.getVarargElementType() != null) { builder.append(renderKeyword("vararg")).append(" "); } return super.visitValueParameterDescriptor(descriptor, builder); diff --git a/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet b/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet new file mode 100644 index 00000000000..2ce06de117c --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/full/VarargTypes.jet @@ -0,0 +1,26 @@ +// KT-389 Wrong type inference for varargs etc. + +import java.util.* + +fun foob(vararg a : Byte) : ByteArray = a +fun fooc(vararg a : Char) : CharArray = a +fun foos(vararg a : Short) : ShortArray = a +fun fooi(vararg a : Int) : IntArray = a +fun fool(vararg a : Long) : LongArray = a +fun food(vararg a : Double) : DoubleArray = a +fun foof(vararg a : Float) : FloatArray = a +fun foob(vararg a : Boolean) : BooleanArray = a +fun foos(vararg a : String) : Array = a + +fun test() { + Arrays.asList(1, 2, 3) + Arrays.asList(1, 2, 3) + + foob(1, 2, 3) + foos(1, 2, 3) + fooc('1', '2', '3') + fooi(1, 2, 3) + fool(1, 2, 3) + food(1.0, 2.0, 3.0) + foof(1.0.flt, 2.0.flt, 3.0.flt) +} \ No newline at end of file From 5e5b793b22244921c73d7d794c7a18ab12ff428e Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 1 Nov 2011 15:46:38 +0100 Subject: [PATCH 31/31] varargs --- .../jet/codegen/ExpressionCodegen.java | 21 ++++++++- .../jetbrains/jet/codegen/JetTypeMapper.java | 21 +++------ .../org/jetbrains/jet/codegen/StackValue.java | 3 ++ .../jetbrains/jet/lang/psi/JetParameter.java | 5 ++ .../org/jetbrains/jet/codegen/VarArgTest.java | 47 ++++++++++++++++--- 5 files changed, 73 insertions(+), 24 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index c0fd4c8b2e2..559b651abcd 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -79,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor { this.intrinsics = state.getIntrinsics(); } - private CallableMethod asCallableMethod(FunctionDescriptor fd) { + private static CallableMethod asCallableMethod(FunctionDescriptor fd) { Method descriptor = ClosureCodegen.erasedInvokeSignature(fd); String owner = ClosureCodegen.getInternalClassName(fd); final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); @@ -1187,7 +1187,24 @@ public class ExpressionCodegen extends JetVisitor { mask |= (1 << index); } else if(resolvedValueArgument instanceof VarargValueArgument) { - throw new UnsupportedOperationException("Varargs are not supported yet"); + VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument; + JetType outType = valueParameterDescriptor.getOutType(); + + Type type = typeMapper.mapType(outType); + assert type.getSort() == Type.ARRAY; + Type elementType = type.getElementType(); + int size = valueArgument.getArgumentExpressions().size(); + + v.iconst(valueArgument.getArgumentExpressions().size()); + v.newarray(elementType); + for(int i = 0; i != size; ++i) { + v.dup(); + v.iconst(i); + gen(valueArgument.getArgumentExpressions().get(i), elementType); + StackValue.arrayElement(elementType, false).store(v); + } + +// throw new UnsupportedOperationException("Varargs are not supported yet"); } else { throw new UnsupportedOperationException(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 3a739179e04..0d44f856737 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -361,10 +361,6 @@ public class JetTypeMapper { if (jetType.equals(standardLibrary.getNullableBooleanType())) { return JL_BOOLEAN_TYPE; } - if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) { - return Type.getType(String.class); - } - if(jetType.equals(standardLibrary.getByteArrayType())){ return ARRAY_BYTE_TYPE; } @@ -390,6 +386,10 @@ public class JetTypeMapper { return ARRAY_BOOL_TYPE; } + if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) { + return Type.getType(String.class); + } + DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); if (standardLibrary.getArray().equals(descriptor)) { if (jetType.getArguments().size() != 1) { @@ -491,9 +491,6 @@ public class JetTypeMapper { } for (ValueParameterDescriptor parameter : parameters) { Type type = mapType(parameter.getOutType()); - if(parameter.getVarargElementType() != null) { - type = Type.getType("[" + type.getDescriptor()); - } valueParameterTypes.add(type); parameterTypes.add(type); } @@ -517,7 +514,7 @@ public class JetTypeMapper { return mapToCallableMethod(functionDescriptor, kind); } - CallableMethod mapToCallableMethod(PsiMethod method) { + static CallableMethod mapToCallableMethod(PsiMethod method) { final PsiClass containingClass = method.getContainingClass(); String owner = jvmName(containingClass); Method signature = getMethodDescriptor(method); @@ -591,13 +588,7 @@ public class JetTypeMapper { parameterTypes.add(mapType(receiver.getType())); } for (ValueParameterDescriptor parameter : parameters) { - if(parameter.getVarargElementType() != null) { - Type type = mapType(parameter.getOutType()); - type = Type.getType("[" + type.getDescriptor()); - parameterTypes.add(type); - } - else - parameterTypes.add(mapType(parameter.getOutType())); + parameterTypes.add(mapType(parameter.getOutType())); } Type returnType = mapReturnType(f.getReturnType()); return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 52ff48a6183..5b2f2488b08 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -681,6 +681,9 @@ public abstract class StackValue { case Type.INT: return JetTypeMapper.TYPE_SHARED_INT; + case Type.LONG: + return JetTypeMapper.TYPE_SHARED_LONG; + case Type.BOOLEAN: return JetTypeMapper.TYPE_SHARED_BOOLEAN; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetParameter.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetParameter.java index 44c6cbfc276..1b4fbe1c8d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetParameter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetParameter.java @@ -59,6 +59,11 @@ public class JetParameter extends JetNamedDeclaration { return findChildByType(JetTokens.VAR_KEYWORD) != null || isRef(); } + public boolean isVarArg() { + JetModifierList modifierList = getModifierList(); + return modifierList != null && modifierList.getModifierNode(JetTokens.VARARG_KEYWORD) != null; + } + @Nullable public ASTNode getValOrVarNode() { ASTNode val = getNode().findChildByType(JetTokens.VAL_KEYWORD); diff --git a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java index 9dca1094568..ea4174110bf 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/VarArgTest.java @@ -8,22 +8,55 @@ import java.lang.reflect.Method; */ public class VarArgTest extends CodegenTestCase { public void testStringArray () throws InvocationTargetException, IllegalAccessException { - /* loadText("fun test(vararg ts: String) = ts"); System.out.println(generateToText()); final Method main = generateFunction(); - Object[] args = {"mama", "papa"}; - assertTrue(args == main.invoke(null, args)); - */ + String[] args = {"mama", "papa"}; + assertTrue(args == main.invoke(null, new Object[]{ args } )); } public void testIntArray () throws InvocationTargetException, IllegalAccessException { - /* loadText("fun test(vararg ts: Int) = ts"); System.out.println(generateToText()); final Method main = generateFunction(); int[] args = {3, 4}; - assertTrue(args == main.invoke(null, args)); - */ + assertTrue(args == main.invoke(null, new Object[]{ args })); + } + + public void testIntArrayKotlinNoArgs () throws InvocationTargetException, IllegalAccessException { + loadText("fun test() = testf(); fun testf(vararg ts: Int) = ts"); + System.out.println(generateToText()); + final Method main = generateFunction(); + Object res = main.invoke(null, new Object[]{}); + assertTrue(((int[])res).length == 0); + } + + public void testIntArrayKotlin () throws InvocationTargetException, IllegalAccessException { + loadText("fun test() = testf(239, 7); fun testf(vararg ts: Int) = ts"); + System.out.println(generateToText()); + final Method main = generateFunction(); + Object res = main.invoke(null, new Object[]{}); + assertTrue(((int[])res).length == 2); + assertTrue(((int[])res)[0] == 239); + assertTrue(((int[])res)[1] == 7); + } + + public void testNullableIntArrayKotlin () throws InvocationTargetException, IllegalAccessException { + loadText("fun test() = testf(239.byt, 7.byt); fun testf(vararg ts: Byte?) = ts"); + System.out.println(generateToText()); + final Method main = generateFunction(); + Object res = main.invoke(null, new Object[]{}); + assertTrue(((Byte[])res).length == 2); + assertTrue(((Byte[])res)[0] == (byte)239); + assertTrue(((Byte[])res)[1] == 7); + } + + public void testIntArrayKotlinObj () throws InvocationTargetException, IllegalAccessException { + loadText("fun test() = testf(\"239\"); fun testf(vararg ts: String) = ts"); + System.out.println(generateToText()); + final Method main = generateFunction(); + Object res = main.invoke(null, new Object[]{}); + assertTrue(((String[])res).length == 1); + assertTrue(((String[])res)[0].equals("239")); } }