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/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a76f5e3d782..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(); @@ -1238,29 +1255,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/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/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 947cf407491..0d44f856737 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.*; @@ -360,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; } @@ -389,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) { @@ -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: @@ -462,9 +491,6 @@ public class JetTypeMapper { } for (ValueParameterDescriptor parameter : parameters) { Type type = mapType(parameter.getOutType()); - if(parameter.isVararg()) { - type = Type.getType("[" + type.getDescriptor()); - } valueParameterTypes.add(type); parameterTypes.add(type); } @@ -488,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); @@ -562,13 +588,7 @@ public class JetTypeMapper { parameterTypes.add(mapType(receiver.getType())); } for (ValueParameterDescriptor parameter : parameters) { - if(parameter.isVararg()) { - 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/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/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/CompileSession.java b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java new file mode 100644 index 00000000000..120a431fe08 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/CompileSession.java @@ -0,0 +1,98 @@ +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; +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, Predicates.alwaysTrue(), 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 68f4809ee36..7f047272fe2 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -1,48 +1,45 @@ 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.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 jet.modules.IModuleBuilder; +import jet.modules.IModuleSetBuilder; 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.codegen.GeneratedClassLoader; 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.lang.reflect.Method; 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 = "src", description = "source file or directory", required = true) + @Argument(value = "jar", description = "jar file name") + public String jar; + @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) { @@ -52,7 +49,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; } @@ -68,107 +65,238 @@ public class KotlinCompiler { if (rtJar == null) return; environment.addToClasspath(rtJar); - - VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(arguments.src); - if (vFile == null) { - System.out.print("File/directory not found: " + arguments.src); - return; - } - - Project project = environment.getProject(); - GenerationState generationState = new GenerationState(project, false); - List namespaces = Lists.newArrayList(); - if(vFile.isDirectory()) { - File dir = new File(vFile.getPath()); - addFiles(environment, project, namespaces, dir); + final File unpackedRuntimePath = getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + environment.addToClasspath(unpackedRuntimePath); } else { - PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile); - if (psiFile instanceof JetFile) { - namespaces.add(((JetFile) psiFile).getRootNamespace()); + final File runtimeJarPath = getRuntimeJarPath(); + if (runtimeJarPath != null && runtimeJarPath.exists()) { + environment.addToClasspath(runtimeJarPath); } else { - System.out.print("Not a Kotlin file: " + vFile.getPath()); + System.out.println("No runtime library found"); return; } } - BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY); + if (arguments.module != null) { + compileModuleScript(environment, arguments.module); + return; + } - ErrorCollector errorCollector = new ErrorCollector(bindingContext); - errorCollector.report(); + CompileSession session = new CompileSession(environment); + session.addSources(arguments.src); - if (!errorCollector.hasErrors) { - 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"); + String mainClass = null; + for (JetNamespace namespace : session.getSourceFileNamespaces()) { + if (JetMainDetector.hasMain(namespace.getDeclarations())) { + mainClass = namespace.getFQName() + ".namespace"; + break; } - else { - List files = factory.files(); - for (String file : files) { - File target = new File(arguments.outputDir, file); + } + 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 { + System.out.println("Output directory or jar file is not specified - no files will be saved to the disk"); + } + } + + 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) { + 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"); + 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; + } + ClassFileFactory factory = moduleCompileSession.generate(); + writeToJar(factory, new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(), null, true); + } + + 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) { + 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 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 { + 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(unpackedRuntimePath, file); try { - FileUtil.writeToFile(target, factory.asBytes(file)); - System.out.println("Generated classfile: " + target); + stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath))); + FileInputStream fis = new FileInputStream(file); + try { + FileUtil.copy(fis, stream); + } finally { + fis.close(); + } } catch (IOException e) { - System.out.println(e.getMessage()); + throw new RuntimeException(e); } + return true; } - } + }); } - - } - - 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()); + else { + 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); + } } - } - } - } - - } - - 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()); + } finally { + jis.close(); } } else { - addFiles(environment, project, namespaces, file); + System.out.println("Couldn't find runtime library"); + } + } + } + + 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()); } } } 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..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,23 +1,85 @@ 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; +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; +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.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(); + 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, @NotNull final Function> declarationProvider) { + return analyzeFileWithCache(ANALYZING_UTILS, file, declarationProvider); } + 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) { + bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + synchronized (lock) { + try { + BindingContext bindingContext = analyzingUtils.analyzeNamespaces( + file.getProject(), + declarationProvider.fun(file), + Predicates.equalTo(file), + 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.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/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> BINDING_CONTEXT = Key.create("BINDING_CONTEXT"); - private static final Object lock = new Object(); - public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) { return new AnalyzingUtils(importingStrategy); } @@ -69,17 +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 List 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 @@ -111,38 +111,8 @@ 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(); } - 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) { - try { - JetNamespace rootNamespace = file.getRootNamespace(); - BindingContext bindingContext = analyzeNamespace(rootNamespace, 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/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) { 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 bc2a5cd90ab..093f93825d2 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(); @@ -540,6 +515,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) { @@ -564,4 +540,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/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/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index e4fad9c4fd8..b9b3e65ce8e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -46,6 +46,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 37b9a59d796..48a8733ee82 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -1,15 +1,21 @@ 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; 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 @@ -22,35 +28,43 @@ public class TopDownAnalyzer { @NotNull JetSemanticServices semanticServices, @NotNull BindingTrace trace, @NotNull JetScope outerScope, - NamespaceLike owner, - @NotNull List declarations, + @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 List declarations, + @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(); + context.debug("Enter"); + new TypeHierarchyResolver(context).process(outerScope, owner, declarations); new DeclarationResolver(context).process(); new DelegationResolver(context).process(); new OverrideResolver(context).process(); new BodyResolver(context).resolveBehaviorDeclarationBodies(); new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); - new DeclarationsChecker(context).process(); + new DeclarationsChecker(context).process(); + + context.debug("Exit"); + 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); @@ -104,7 +118,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/TraceBasedRedeclarationHandler.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TraceBasedRedeclarationHandler.java index 299b6f63455..36d7edc0328 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TraceBasedRedeclarationHandler.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TraceBasedRedeclarationHandler.java @@ -26,7 +26,7 @@ public class TraceBasedRedeclarationHandler implements RedeclarationHandler { private void report(DeclarationDescriptor first) { PsiElement firstElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, first); if (firstElement != null) { - trace.report(REDECLARATION.on(firstElement)); + trace.report(REDECLARATION.on(firstElement, first.getName())); } else { trace.report(REDECLARATION.on(first, trace.getBindingContext())); 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..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 List declarations) { + public void process(@NotNull JetScope outerScope, @NotNull NamespaceLike owner, @NotNull Collection declarations) { collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes processTypeImports(); 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/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/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 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() { + + } +} 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 + } +} 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 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/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 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/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') diff --git a/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java b/compiler/tests/org/jetbrains/jet/checkers/CheckerTestUtilTest.java index 319e0b06789..06ffed74d04 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, 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 ebb5e91515e..d6ead64cdf1 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, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() { @Override 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/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()); + } } 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")); } } 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/docs/CodeGen2012_Proposal.txt b/docs/CodeGen2012_Proposal.txt new file mode 100644 index 00000000000..879d74bd7b3 --- /dev/null +++ b/docs/CodeGen2012_Proposal.txt @@ -0,0 +1,72 @@ +Code Generation 2012 - Session Proposal Form + +Submission Deadline: Friday December 9th 2011 + +Session title: + +DSLs in Kotlin + +Session type and duration: + +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. + +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! 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: + +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: + +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: + +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 some of the statically typed languages (Java, Scala, C#, C++ etc). + +Availability: + +No constraints + +Detailed Description / Supporting Information + +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: +* 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 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 +Affiliation: JetBrains +Telephone / Skype: andrey.breslav @ skype +Email: andrey.breslav@jetbrains.com +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 diff --git a/examples/src/Hello.kts b/examples/src/Hello.kts new file mode 100644 index 00000000000..c7086636e56 --- /dev/null +++ b/examples/src/Hello.kts @@ -0,0 +1,7 @@ +import kotlin.modules.ModuleSetBuilder + +fun defineModules(builder: ModuleSetBuilder) { + builder.module("hello") { + source files "HelloNames.kt" + } +} 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 @@ - diff --git a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java index bdcca23ba32..43ca6abd27f 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java @@ -8,7 +8,7 @@ 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; /** @@ -26,7 +26,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 d2be0e6939d..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,12 +55,13 @@ 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()); Set redeclarations = Sets.newHashSet(); for (Diagnostic diagnostic : diagnostics) { + 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) { diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java index c29a35c2ea3..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; @@ -66,16 +67,21 @@ 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()); } } - 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()) { 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..01d853c9d7d --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/compiler/WholeProjectAnalyzerFacade.java @@ -0,0 +1,63 @@ +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; +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 org.jetbrains.jet.plugin.JetFileType; + +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(final JetFile rootFile) { + final Project project = rootFile.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) { + final FileType fileType = FileTypeManager.getInstance().getFileTypeByFile(file); + if (fileType != JetFileType.INSTANCE) return; + PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (psiFile instanceof JetFile) { + if (rootFile.getOriginalFile() != psiFile) { + namespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } + } + }); + + } + + namespaces.add(rootFile.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); diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java index dd8011fb41e..b99895b0542 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java @@ -8,9 +8,12 @@ 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 java.util.List; +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; /** * @author yole @@ -22,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; @@ -30,14 +44,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()); + return createConfigurationByQName(location.getModule(), configurationContext, getFQName(containingClass)); } 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 +59,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(); diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index f6e97a1cdf1..7e2e25e8715 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -1,15 +1,20 @@ -namespace kotlin.modules +namespace kotlin + +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) { @@ -44,4 +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(); +}