Merge branch 'master' of ssh://git.labs.intellij.net/jet

This commit is contained in:
svtk
2011-11-01 19:12:59 +04:00
72 changed files with 1208 additions and 391 deletions
+1
View File
@@ -29,6 +29,7 @@
<target name="jarRT" depends="compileRT"> <target name="jarRT" depends="compileRT">
<jar destfile="${output}/kotlin-runtime.jar"> <jar destfile="${output}/kotlin-runtime.jar">
<fileset dir="${output}/classes/runtime"/> <fileset dir="${output}/classes/runtime"/>
<fileset dir="${basedir}/stdlib/ktSrc"/>
</jar> </jar>
</target> </target>
@@ -79,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics(); this.intrinsics = state.getIntrinsics();
} }
private CallableMethod asCallableMethod(FunctionDescriptor fd) { private static CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = ClosureCodegen.erasedInvokeSignature(fd); Method descriptor = ClosureCodegen.erasedInvokeSignature(fd);
String owner = ClosureCodegen.getInternalClassName(fd); String owner = ClosureCodegen.getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
@@ -1187,7 +1187,24 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
mask |= (1 << index); mask |= (1 << index);
} }
else if(resolvedValueArgument instanceof VarargValueArgument) { 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 { else {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@@ -1238,29 +1255,44 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override @Override
public StackValue visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, StackValue receiver) { public StackValue visitSafeQualifiedExpression(JetSafeQualifiedExpression expression, StackValue receiver) {
genToJVMStack(expression.getReceiverExpression()); JetExpression expr = expression.getReceiverExpression();
Label ifnull = new Label(); JetType receiverJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression());
Label end = new Label(); Type receiverType = typeMapper.mapType(receiverJetType);
v.dup(); gen(expr, receiverType);
v.ifnull(ifnull); if(receiverType.getSort() != Type.OBJECT && receiverType.getSort() != Type.ARRAY) {
JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()); StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
StackValue propValue = genQualified(StackValue.onStack(typeMapper.mapType(receiverType)), expression.getSelectorExpression()); Type type = propValue.type;
Type type = propValue.type; propValue.put(type, v);
propValue.put(type, v); if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) {
if(JetTypeMapper.isPrimitive(type) && !type.equals(Type.VOID_TYPE)) { StackValue.valueOf(v, type);
StackValue.valueOf(v, type); type = JetTypeMapper.boxType(type);
type = JetTypeMapper.boxType(type); }
}
v.goTo(end);
v.mark(ifnull); return StackValue.onStack(type);
v.pop();
if(!propValue.type.equals(Type.VOID_TYPE)) {
v.aconst(null);
} }
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 @Override
@@ -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);
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method; import org.objectweb.asm.commons.Method;
import java.util.*; import java.util.*;
@@ -360,10 +361,6 @@ public class JetTypeMapper {
if (jetType.equals(standardLibrary.getNullableBooleanType())) { if (jetType.equals(standardLibrary.getNullableBooleanType())) {
return JL_BOOLEAN_TYPE; return JL_BOOLEAN_TYPE;
} }
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
return Type.getType(String.class);
}
if(jetType.equals(standardLibrary.getByteArrayType())){ if(jetType.equals(standardLibrary.getByteArrayType())){
return ARRAY_BYTE_TYPE; return ARRAY_BYTE_TYPE;
} }
@@ -389,6 +386,10 @@ public class JetTypeMapper {
return ARRAY_BOOL_TYPE; return ARRAY_BOOL_TYPE;
} }
if (jetType.equals(standardLibrary.getStringType()) || jetType.equals(standardLibrary.getNullableStringType())) {
return Type.getType(String.class);
}
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (standardLibrary.getArray().equals(descriptor)) { if (standardLibrary.getArray().equals(descriptor)) {
if (jetType.getArguments().size() != 1) { if (jetType.getArguments().size() != 1) {
@@ -415,6 +416,34 @@ public class JetTypeMapper {
throw new UnsupportedOperationException("Unknown type " + jetType); 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) { public static Type boxType(Type asmType) {
switch (asmType.getSort()) { switch (asmType.getSort()) {
case Type.VOID: case Type.VOID:
@@ -462,9 +491,6 @@ public class JetTypeMapper {
} }
for (ValueParameterDescriptor parameter : parameters) { for (ValueParameterDescriptor parameter : parameters) {
Type type = mapType(parameter.getOutType()); Type type = mapType(parameter.getOutType());
if(parameter.isVararg()) {
type = Type.getType("[" + type.getDescriptor());
}
valueParameterTypes.add(type); valueParameterTypes.add(type);
parameterTypes.add(type); parameterTypes.add(type);
} }
@@ -488,7 +514,7 @@ public class JetTypeMapper {
return mapToCallableMethod(functionDescriptor, kind); return mapToCallableMethod(functionDescriptor, kind);
} }
CallableMethod mapToCallableMethod(PsiMethod method) { static CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass(); final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass); String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method); Method signature = getMethodDescriptor(method);
@@ -562,13 +588,7 @@ public class JetTypeMapper {
parameterTypes.add(mapType(receiver.getType())); parameterTypes.add(mapType(receiver.getType()));
} }
for (ValueParameterDescriptor parameter : parameters) { for (ValueParameterDescriptor parameter : parameters) {
if(parameter.isVararg()) { parameterTypes.add(mapType(parameter.getOutType()));
Type type = mapType(parameter.getOutType());
type = Type.getType("[" + type.getDescriptor());
parameterTypes.add(type);
}
else
parameterTypes.add(mapType(parameter.getOutType()));
} }
Type returnType = mapReturnType(f.getReturnType()); Type returnType = mapReturnType(f.getReturnType());
return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); return new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
@@ -681,6 +681,9 @@ public abstract class StackValue {
case Type.INT: case Type.INT:
return JetTypeMapper.TYPE_SHARED_INT; return JetTypeMapper.TYPE_SHARED_INT;
case Type.LONG:
return JetTypeMapper.TYPE_SHARED_LONG;
case Type.BOOLEAN: case Type.BOOLEAN:
return JetTypeMapper.TYPE_SHARED_BOOLEAN; return JetTypeMapper.TYPE_SHARED_BOOLEAN;
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.ExpressionCodegen;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@@ -21,6 +22,10 @@ public class BinaryOp implements IntrinsicMethod {
@Override @Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) { public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if(nullable) {
expectedType = JetTypeMapper.unboxType(expectedType);
}
if (arguments.size() == 1) { if (arguments.size() == 1) {
// intrinsic is called as an ordinary function // intrinsic is called as an ordinary function
if (receiver != null) { if (receiver != null) {
@@ -33,6 +38,10 @@ public class BinaryOp implements IntrinsicMethod {
codegen.gen(arguments.get(1), expectedType); codegen.gen(arguments.get(1), expectedType);
} }
v.visitInsn(expectedType.getOpcode(opcode)); v.visitInsn(expectedType.getOpcode(opcode));
if(nullable) {
StackValue.onStack(expectedType).put(expectedType = JetTypeMapper.boxType(expectedType), v);
}
return StackValue.onStack(expectedType); return StackValue.onStack(expectedType);
} }
} }
+1
View File
@@ -10,6 +10,7 @@
<orderEntry type="module" module-name="backend" /> <orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="frontend" /> <orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" /> <orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" />
</component> </component>
</module> </module>
@@ -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<JetNamespace> mySourceFileNamespaces = new ArrayList<JetNamespace>();
private final List<JetNamespace> myLibrarySourceFileNamespaces = new ArrayList<JetNamespace>();
private List<String> myErrors = new ArrayList<String>();
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<JetNamespace> 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<JetNamespace> allNamespaces = new ArrayList<JetNamespace>(mySourceFileNamespaces);
allNamespaces.addAll(myLibrarySourceFileNamespaces);
myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.<PsiFile>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();
}
}
@@ -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<PsiFile,DiagnosticWithTextRange> maps = LinkedHashMultimap.<PsiFile, DiagnosticWithTextRange>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<DiagnosticWithTextRange> diagnosticWithTextRanges = maps.get(psiFile);
for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) {
String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange);
System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage());
}
}
}
}
}
@@ -1,48 +1,45 @@
package org.jetbrains.jet.cli; 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.Disposable;
import com.intellij.openapi.project.Project; import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile; import com.intellij.util.Processor;
import com.intellij.psi.PsiManager;
import com.sampullara.cli.Args; import com.sampullara.cli.Args;
import com.sampullara.cli.Argument; import com.sampullara.cli.Argument;
import jet.modules.IModuleBuilder;
import jet.modules.IModuleSetBuilder;
import org.jetbrains.jet.JetCoreEnvironment; import org.jetbrains.jet.JetCoreEnvironment;
import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.GeneratedClassLoader;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithTextRange;
import org.jetbrains.jet.lang.diagnostics.Severity;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.plugin.JetMainDetector;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.jar.*;
/** /**
* @author yole * @author yole
* @author alex.tkachman * @author alex.tkachman
*/ */
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class KotlinCompiler { public class KotlinCompiler {
public static class Arguments { public static class Arguments {
@Argument(value = "output", description = "output directory") @Argument(value = "output", description = "output directory")
public String outputDir; 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; public String src;
@Argument(value = "module", description = "module to compile")
public String module;
} }
public static void main(String[] args) { public static void main(String[] args) {
@@ -52,7 +49,7 @@ public class KotlinCompiler {
Args.parse(arguments, args); Args.parse(arguments, args);
} }
catch (Throwable t) { catch (Throwable t) {
System.out.println("Usage: KotlinCompiler -output <outputDir> -src <filename or dirname>"); System.out.println("Usage: KotlinCompiler [-output <outputDir>|-jar <jarFileName>] -src <filename or dirname>");
t.printStackTrace(); t.printStackTrace();
return; return;
} }
@@ -68,107 +65,238 @@ public class KotlinCompiler {
if (rtJar == null) return; if (rtJar == null) return;
environment.addToClasspath(rtJar); environment.addToClasspath(rtJar);
final File unpackedRuntimePath = getUnpackedRuntimePath();
VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(arguments.src); if (unpackedRuntimePath != null) {
if (vFile == null) { environment.addToClasspath(unpackedRuntimePath);
System.out.print("File/directory not found: " + arguments.src);
return;
}
Project project = environment.getProject();
GenerationState generationState = new GenerationState(project, false);
List<JetNamespace> namespaces = Lists.newArrayList();
if(vFile.isDirectory()) {
File dir = new File(vFile.getPath());
addFiles(environment, project, namespaces, dir);
} }
else { else {
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile); final File runtimeJarPath = getRuntimeJarPath();
if (psiFile instanceof JetFile) { if (runtimeJarPath != null && runtimeJarPath.exists()) {
namespaces.add(((JetFile) psiFile).getRootNamespace()); environment.addToClasspath(runtimeJarPath);
} }
else { else {
System.out.print("Not a Kotlin file: " + vFile.getPath()); System.out.println("No runtime library found");
return; 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); CompileSession session = new CompileSession(environment);
errorCollector.report(); session.addSources(arguments.src);
if (!errorCollector.hasErrors) { String mainClass = null;
generationState.compileCorrectNamespaces(bindingContext, namespaces); for (JetNamespace namespace : session.getSourceFileNamespaces()) {
if (JetMainDetector.hasMain(namespace.getDeclarations())) {
final ClassFileFactory factory = generationState.getFactory(); mainClass = namespace.getFQName() + ".namespace";
if(arguments.outputDir == null) { break;
System.out.println("Output directory is not specified - no files will be saved to the disk");
} }
else { }
List<String> files = factory.files(); if (!session.analyze()) {
for (String file : files) { return;
File target = new File(arguments.outputDir, file); }
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<File>() {
@Override
public boolean process(File file) {
if (file.isDirectory()) return true;
final String relativePath = FileUtil.getRelativePath(unpackedRuntimePath, file);
try { try {
FileUtil.writeToFile(target, factory.asBytes(file)); stream.putNextEntry(new JarEntry(FileUtil.toSystemIndependentName(relativePath)));
System.out.println("Generated classfile: " + target); FileInputStream fis = new FileInputStream(file);
try {
FileUtil.copy(fis, stream);
} finally {
fis.close();
}
} catch (IOException e) { } catch (IOException e) {
System.out.println(e.getMessage()); throw new RuntimeException(e);
} }
return true;
} }
} });
} }
else {
} File runtimeJarPath = getRuntimeJarPath();
if (runtimeJarPath != null) {
private static class ErrorCollector { JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath));
Multimap<PsiFile,DiagnosticWithTextRange> maps = LinkedHashMultimap.<PsiFile, DiagnosticWithTextRange>create(); try {
while (true) {
boolean hasErrors; JarEntry e = jis.getNextJarEntry();
if (e == null) {
public ErrorCollector(BindingContext bindingContext) { break;
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { }
report(diagnostic); if (FileUtil.getExtension(e.getName()).equals("class")) {
} stream.putNextEntry(e);
} FileUtil.copy(jis, stream);
}
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<DiagnosticWithTextRange> diagnosticWithTextRanges = maps.get(psiFile);
for (DiagnosticWithTextRange diagnosticWithTextRange : diagnosticWithTextRanges) {
String position = DiagnosticUtils.formatPosition(diagnosticWithTextRange);
System.out.println("\t" + diagnosticWithTextRange.getSeverity().toString() + ": " + position + " " + diagnosticWithTextRange.getMessage());
} }
} } finally {
} jis.close();
}
}
private static void addFiles(JavaCoreEnvironment environment, Project project, List<JetNamespace> namespaces, File dir) {
for(File file : dir.listFiles()) {
if(!file.isDirectory()) {
VirtualFile virtualFile = environment.getLocalFileSystem().findFileByPath(file.getAbsolutePath());
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (psiFile instanceof JetFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace());
} }
} }
else { else {
addFiles(environment, project, namespaces, file); System.out.println("Couldn't find runtime library");
}
}
}
private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) {
List<String> 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());
} }
} }
} }
@@ -1,23 +1,85 @@
package org.jetbrains.jet.lang.resolve.java; 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.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; 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.JetFile;
import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import java.util.Collection;
import java.util.Collections;
/** /**
* @author abreslav * @author abreslav
*/ */
public class AnalyzerFacade { public class AnalyzerFacade {
public static final Function<JetFile, Collection<JetDeclaration>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetDeclaration>>() {
@Override
public Collection<JetDeclaration> fun(JetFile file) {
return Collections.<JetDeclaration>singleton(file.getRootNamespace());
}
};
private static final AnalyzingUtils ANALYZING_UTILS = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS);
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { 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) { public static BindingContext analyzeFileWithCache(@NotNull final JetFile file, @NotNull final Function<JetFile, Collection<JetDeclaration>> declarationProvider) {
return AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeFileWithCache(file); return analyzeFileWithCache(ANALYZING_UTILS, file, declarationProvider);
} }
public static BindingContext analyzeFileWithCache(@NotNull final AnalyzingUtils analyzingUtils,
@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetDeclaration>> declarationProvider) {
// TODO : Synchronization?
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
synchronized (lock) {
try {
BindingContext bindingContext = analyzingUtils.analyzeNamespaces(
file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(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<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
}
}
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
} }
@@ -300,15 +300,26 @@ public class JavaDescriptorResolver {
for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) { for (int i = 0, parametersLength = parameters.length; i < parametersLength; i++) {
PsiParameter parameter = parameters[i]; PsiParameter parameter = parameters[i];
String name = parameter.getName(); 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( result.add(new ValueParameterDescriptorImpl(
containingDeclaration, containingDeclaration,
i, i,
Collections.<AnnotationDescriptor>emptyList(), // TODO Collections.<AnnotationDescriptor>emptyList(), // TODO
name == null ? "p" + i : name, name == null ? "p" + i : name,
null, // TODO : review null, // TODO : review
semanticServices.getTypeTransformer().transformToType(parameter.getType()), outType,
false, false,
parameter.isVarArgs() varargElementType
)); ));
} }
return result; return result;
@@ -16,35 +16,6 @@ import java.util.*;
* @author abreslav * @author abreslav
*/ */
public class FunctionDescriptorUtil { 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<ValueParameterDescriptor> 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<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) { public static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap(); if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
@@ -69,13 +40,16 @@ public class FunctionDescriptorUtil {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i); ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
// TODO : Lazy? // TODO : Lazy?
JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getOutType(), Variance.IN_VARIANCE); 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; if (substitutedType == null) return null;
result.add(new ValueParameterDescriptorImpl( result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor, substitutedDescriptor,
unsubstitutedValueParameter, unsubstitutedValueParameter,
unsubstitutedValueParameter.getAnnotations(), unsubstitutedValueParameter.getAnnotations(),
unsubstitutedValueParameter.getInType() == null ? null : substitutedType, unsubstitutedValueParameter.getInType() == null ? null : substitutedType,
substitutedType substitutedType,
substituteVarargElementType
)); ));
} }
return result; return result;
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.descriptors; package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
/** /**
@@ -15,7 +16,7 @@ public interface ValueParameterDescriptor extends VariableDescriptor {
int getIndex(); int getIndex();
boolean hasDefaultValue(); boolean hasDefaultValue();
boolean isRef(); boolean isRef();
boolean isVararg(); @Nullable JetType getVarargElementType();
@Override @Override
@NotNull @NotNull
@@ -26,4 +27,5 @@ public interface ValueParameterDescriptor extends VariableDescriptor {
@NotNull @NotNull
ValueParameterDescriptor copy(DeclarationDescriptor newOwner); ValueParameterDescriptor copy(DeclarationDescriptor newOwner);
} }
@@ -14,7 +14,7 @@ import java.util.List;
*/ */
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor { public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor {
private final boolean hasDefaultValue; private final boolean hasDefaultValue;
private final boolean isVararg; private final JetType varargElementType;
private final boolean isVar; private final boolean isVar;
private final int index; private final int index;
private final ValueParameterDescriptor original; private final ValueParameterDescriptor original;
@@ -27,12 +27,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@Nullable JetType inType, @Nullable JetType inType,
@NotNull JetType outType, @NotNull JetType outType,
boolean hasDefaultValue, boolean hasDefaultValue,
boolean isVararg) { @Nullable JetType varargElementType) {
super(containingDeclaration, annotations, name, inType, outType); super(containingDeclaration, annotations, name, inType, outType);
this.original = this; this.original = this;
this.index = index; this.index = index;
this.hasDefaultValue = hasDefaultValue; this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg; this.varargElementType = varargElementType;
this.isVar = inType != null; this.isVar = inType != null;
} }
@@ -41,13 +41,14 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull ValueParameterDescriptor original, @NotNull ValueParameterDescriptor original,
@NotNull List<AnnotationDescriptor> annotations, @NotNull List<AnnotationDescriptor> annotations,
@Nullable JetType inType, @Nullable JetType inType,
@NotNull JetType outType @NotNull JetType outType,
@Nullable JetType varargElementType
) { ) {
super(containingDeclaration, annotations, original.getName(), inType, outType); super(containingDeclaration, annotations, original.getName(), inType, outType);
this.original = original; this.original = original;
this.index = original.getIndex(); this.index = original.getIndex();
this.hasDefaultValue = original.hasDefaultValue(); this.hasDefaultValue = original.hasDefaultValue();
this.isVararg = original.isVararg(); this.varargElementType = varargElementType;
this.isVar = inType != null; this.isVar = inType != null;
} }
@@ -76,9 +77,9 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@Override @Nullable
public boolean isVararg() { public JetType getVarargElementType() {
return isVararg; return varargElementType;
} }
@NotNull @NotNull
@@ -106,6 +107,6 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull @NotNull
@Override @Override
public ValueParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) { 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);
} }
} }
@@ -15,8 +15,8 @@ import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR;
public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement<PsiElement> { public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement<PsiElement> {
public class SimpleRedeclarationDiagnostic extends DiagnosticWithPsiElementImpl<PsiElement> implements RedeclarationDiagnostic { public class SimpleRedeclarationDiagnostic extends DiagnosticWithPsiElementImpl<PsiElement> implements RedeclarationDiagnostic {
public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement) { public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement, @NotNull String name) {
super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration", psiElement); super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration: " + name, psiElement);
} }
} }
@@ -66,7 +66,7 @@ public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement<PsiEle
@NotNull @NotNull
@Override @Override
public String getMessage() { public String getMessage() {
return "Redeclaration"; return "Redeclaration: " + duplicatingDescriptor.getName();
} }
@NotNull @NotNull
@@ -16,8 +16,8 @@ public class RedeclarationDiagnosticFactory extends AbstractDiagnosticFactory {
public RedeclarationDiagnosticFactory() {} public RedeclarationDiagnosticFactory() {}
public RedeclarationDiagnostic on(@NotNull PsiElement duplicatingElement) { public RedeclarationDiagnostic on(@NotNull PsiElement duplicatingElement, @NotNull String name) {
return new RedeclarationDiagnostic.SimpleRedeclarationDiagnostic(duplicatingElement); return new RedeclarationDiagnostic.SimpleRedeclarationDiagnostic(duplicatingElement, name);
} }
public Diagnostic on(DeclarationDescriptor duplicatingDescriptor, BindingContext contextToResolveToDeclaration) { public Diagnostic on(DeclarationDescriptor duplicatingDescriptor, BindingContext contextToResolveToDeclaration) {
@@ -167,7 +167,7 @@ public class JetParsing extends AbstractJetParsing {
} }
PsiBuilder.Marker reference = mark(); PsiBuilder.Marker reference = mark();
expect(IDENTIFIER, "Expecting qualified name", TokenSet.create(DOT, AS_KEYWORD)); expect(IDENTIFIER, "Expecting qualified name");
reference.done(REFERENCE_EXPRESSION); reference.done(REFERENCE_EXPRESSION);
while (at(DOT) && lookahead(1) != MUL) { while (at(DOT) && lookahead(1) != MUL) {
advance(); // DOT advance(); // DOT
@@ -1,7 +1,6 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
@@ -105,17 +104,6 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
return body.getProperties(); return body.getProperties();
} }
public String getFQName() {
JetNamedDeclaration parent = PsiTreeUtil.getParentOfType(this, JetNamespace.class, JetClass.class);
if (parent instanceof JetNamespace) {
return ((JetNamespace) parent).getFQName() + "." + getName();
}
if (parent instanceof JetClass) {
return ((JetClass) parent).getFQName() + "." + getName();
}
return getName();
}
public boolean isTrait() { public boolean isTrait() {
return findChildByType(JetTokens.TRAIT_KEYWORD) != null; return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
} }
@@ -59,6 +59,11 @@ public class JetParameter extends JetNamedDeclaration {
return findChildByType(JetTokens.VAR_KEYWORD) != null || isRef(); return findChildByType(JetTokens.VAR_KEYWORD) != null || isRef();
} }
public boolean isVarArg() {
JetModifierList modifierList = getModifierList();
return modifierList != null && modifierList.getModifierNode(JetTokens.VARARG_KEYWORD) != null;
}
@Nullable @Nullable
public ASTNode getValOrVarNode() { public ASTNode getValOrVarNode() {
ASTNode val = getNode().findChildByType(JetTokens.VAL_KEYWORD); ASTNode val = getNode().findChildByType(JetTokens.VAL_KEYWORD);
@@ -1,40 +1,33 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.intellij.openapi.progress.ProcessCanceledException; import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiErrorElement; import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.util.CachedValue; import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.diagnostics.*; import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticHolder;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.psi.JetDeclaration; 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.psi.JetNamespace;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
//import org.jetbrains.jet.lang.resolve.java.JavaPackageScope;
//import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices;
/** /**
* @author abreslav * @author abreslav
*/ */
public class AnalyzingUtils { public class AnalyzingUtils {
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
private static final Object lock = new Object();
public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) { public static AnalyzingUtils getInstance(@NotNull ImportingStrategy importingStrategy) {
return new AnalyzingUtils(importingStrategy); return new AnalyzingUtils(importingStrategy);
} }
@@ -69,17 +62,24 @@ public class AnalyzingUtils {
Project project = namespace.getProject(); Project project = namespace.getProject();
List<JetDeclaration> declarations = Collections.<JetDeclaration>singletonList(namespace); List<JetDeclaration> declarations = Collections.<JetDeclaration>singletonList(namespace);
return analyzeNamespaces(project, declarations, flowDataTraceFactory); return analyzeNamespaces(project, declarations, Predicates.equalTo(namespace.getContainingFile()), flowDataTraceFactory);
} }
public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { public BindingContext analyzeNamespaces(
@NotNull Project project,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingTraceContext bindingTraceContext = new BindingTraceContext(); BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project); JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope(); JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
ModuleDescriptor owner = new ModuleDescriptor("<module>"); ModuleDescriptor owner = new ModuleDescriptor("<module>");
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); importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope);
scope.importScope(libraryScope);
TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) { TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) {
@Override @Override
@@ -111,38 +111,8 @@ public class AnalyzingUtils {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
throw new IllegalStateException("Must be guaranteed not to happen by the parser"); throw new IllegalStateException("Must be guaranteed not to happen by the parser");
} }
}, declarations, flowDataTraceFactory); }, declarations, filesToAnalyzeCompletely, flowDataTraceFactory);
return bindingTraceContext.getBindingContext(); return bindingTraceContext.getBindingContext();
} }
public BindingContext analyzeFileWithCache(@NotNull final JetFile file) {
// TODO : Synchronization?
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
synchronized (lock) {
try {
JetNamespace rootNamespace = file.getRootNamespace();
BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(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<BindingContext>(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT);
}
}
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
} }
@@ -8,6 +8,9 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
* @author abreslav * @author abreslav
*/ */
public class BindingContextUtils { public class BindingContextUtils {
private BindingContextUtils() {
}
public static PsiElement resolveToDeclarationPsiElement(BindingContext bindingContext, JetReferenceExpression referenceExpression) { public static PsiElement resolveToDeclarationPsiElement(BindingContext bindingContext, JetReferenceExpression referenceExpression) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression); DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, referenceExpression);
if (declarationDescriptor == null) { if (declarationDescriptor == null) {
@@ -71,7 +71,6 @@ public class BodyResolver {
} }
public void resolveBehaviorDeclarationBodies() { public void resolveBehaviorDeclarationBodies() {
resolveDelegationSpecifierLists(); resolveDelegationSpecifierLists();
@@ -86,34 +85,6 @@ public class BodyResolver {
computeDeferredTypes(); computeDeferredTypes();
} }
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> 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() { private void resolveDelegationSpecifierLists() {
// TODO : Make sure the same thing is not initialized twice // TODO : Make sure the same thing is not initialized twice
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
@@ -125,6 +96,7 @@ public class BodyResolver {
} }
private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) { private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
if (!context.completeAnalysisNeeded(jetClass)) return;
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor(); final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
final JetScope scopeForConstructor = primaryConstructor == null final JetScope scopeForConstructor = primaryConstructor == null
? null ? null
@@ -278,7 +250,6 @@ public class BodyResolver {
} }
private void resolveClassAnnotations() { private void resolveClassAnnotations() {
} }
private void resolveAnonymousInitializers() { private void resolveAnonymousInitializers() {
@@ -291,6 +262,7 @@ public class BodyResolver {
} }
private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) {
if (!context.completeAnalysisNeeded(jetClassOrObject)) return;
List<JetClassInitializer> anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); List<JetClassInitializer> anonymousInitializers = jetClassOrObject.getAnonymousInitializers();
if (jetClassOrObject.hasPrimaryConstructor()) { if (jetClassOrObject.hasPrimaryConstructor()) {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -320,6 +292,7 @@ public class BodyResolver {
} }
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) { private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
if (!context.completeAnalysisNeeded(declaration)) return;
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false); final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
@@ -419,6 +392,7 @@ public class BodyResolver {
Set<JetProperty> processed = Sets.newHashSet(); Set<JetProperty> processed = Sets.newHashSet();
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
JetClass jetClass = entry.getKey(); JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) continue;
MutableClassDescriptor classDescriptor = entry.getValue(); MutableClassDescriptor classDescriptor = entry.getValue();
for (JetProperty property : jetClass.getProperties()) { for (JetProperty property : jetClass.getProperties()) {
@@ -444,6 +418,7 @@ public class BodyResolver {
// Top-level properties & properties of objects // Top-level properties & properties of objects
for (Map.Entry<JetProperty, PropertyDescriptor> entry : this.context.getProperties().entrySet()) { for (Map.Entry<JetProperty, PropertyDescriptor> entry : this.context.getProperties().entrySet()) {
JetProperty property = entry.getKey(); JetProperty property = entry.getKey();
if (!context.completeAnalysisNeeded(property)) return;
if (processed.contains(property)) continue; if (processed.contains(property)) continue;
final PropertyDescriptor propertyDescriptor = entry.getValue(); final PropertyDescriptor propertyDescriptor = entry.getValue();
@@ -540,6 +515,7 @@ public class BodyResolver {
@NotNull JetDeclarationWithBody function, @NotNull JetDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
@NotNull JetScope declaringScope) { @NotNull JetScope declaringScope) {
if (!context.completeAnalysisNeeded(function)) return;
JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) { if (bodyExpression != null) {
@@ -564,4 +540,31 @@ public class BodyResolver {
assert functionDescriptor.getReturnType() != null; assert functionDescriptor.getReturnType() != null;
} }
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> 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
}
}
}
}
}
} }
@@ -246,21 +246,56 @@ public class ClassDescriptorResolver {
@NotNull @NotNull
public MutableValueParameterDescriptor resolveValueParameterDescriptor(DeclarationDescriptor declarationDescriptor, JetParameter valueParameter, int index, JetType type) { 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( MutableValueParameterDescriptor valueParameterDescriptor = new ValueParameterDescriptorImpl(
declarationDescriptor, declarationDescriptor,
index, index,
annotationResolver.createAnnotationStubs(valueParameter.getModifierList()), annotationResolver.createAnnotationStubs(valueParameter.getModifierList()),
JetPsiUtil.safeName(valueParameter.getName()), JetPsiUtil.safeName(valueParameter.getName()),
valueParameter.isMutable() ? type : null, valueParameter.isMutable() ? variableType : null,
type, variableType,
valueParameter.getDefaultValue() != null, valueParameter.getDefaultValue() != null,
valueParameter.hasModifier(JetTokens.VARARG_KEYWORD) varargElementType
); );
trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor); trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
return 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<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) { public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>(); List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) { for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
@@ -46,6 +46,8 @@ public class ControlFlowAnalyzer {
JetNamedFunction function = entry.getKey(); JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue(); FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
? NO_EXPECTED_TYPE ? NO_EXPECTED_TYPE
: functionDescriptor.getReturnType(); : functionDescriptor.getReturnType();
@@ -40,7 +40,8 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) { for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass aClass = entry.getKey(); JetClass aClass = entry.getKey();
MutableClassDescriptor classDescriptor = entry.getValue(); MutableClassDescriptor classDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(aClass)) continue;
checkClass(aClass, classDescriptor); checkClass(aClass, classDescriptor);
checkModifiers(aClass.getModifierList()); checkModifiers(aClass.getModifierList());
} }
@@ -50,6 +51,7 @@ public class DeclarationsChecker {
JetObjectDeclaration objectDeclaration = entry.getKey(); JetObjectDeclaration objectDeclaration = entry.getKey();
MutableClassDescriptor objectDescriptor = entry.getValue(); MutableClassDescriptor objectDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(objectDeclaration)) continue;
checkObject(objectDeclaration, objectDescriptor); checkObject(objectDeclaration, objectDescriptor);
} }
@@ -58,6 +60,7 @@ public class DeclarationsChecker {
JetNamedFunction function = entry.getKey(); JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue(); FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
checkFunction(function, functionDescriptor); checkFunction(function, functionDescriptor);
checkModifiers(function.getModifierList()); checkModifiers(function.getModifierList());
} }
@@ -67,6 +70,7 @@ public class DeclarationsChecker {
JetProperty property = entry.getKey(); JetProperty property = entry.getKey();
PropertyDescriptor propertyDescriptor = entry.getValue(); PropertyDescriptor propertyDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(property)) continue;
checkProperty(property, propertyDescriptor); checkProperty(property, propertyDescriptor);
checkModifiers(property.getModifierList()); checkModifiers(property.getModifierList());
} }
@@ -77,6 +81,7 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) { for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue(); MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey(); JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) return;
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) { if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) { for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) { if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
@@ -1,13 +1,18 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; 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.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import java.io.PrintStream;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -32,10 +37,42 @@ import java.util.Set;
private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap(); private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet(); private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace) { private final Predicate<PsiFile> analyzeCompletely;
private StringBuilder debugOutput;
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate<PsiFile> analyzeCompletely) {
this.trace = new ObservableBindingTrace(trace); this.trace = new ObservableBindingTrace(trace);
this.semanticServices = semanticServices; this.semanticServices = semanticServices;
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace); 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() { public ObservableBindingTrace getTrace() {
@@ -1,15 +1,21 @@
package org.jetbrains.jet.lang.resolve; 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.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.*; 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.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
@@ -22,35 +28,43 @@ public class TopDownAnalyzer {
@NotNull JetSemanticServices semanticServices, @NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull JetScope outerScope, @NotNull JetScope outerScope,
NamespaceLike owner, @NotNull NamespaceLike owner,
@NotNull List<? extends JetDeclaration> declarations, @NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false); process(semanticServices, trace, outerScope, owner, declarations, analyzeCompletely, flowDataTraceFactory, false);
} }
private static void process( private static void process(
@NotNull JetSemanticServices semanticServices, @NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull JetScope outerScope, @NotNull JetScope outerScope,
NamespaceLike owner, @NotNull NamespaceLike owner,
@NotNull List<? extends JetDeclaration> declarations, @NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
boolean declaredLocally) { 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 TypeHierarchyResolver(context).process(outerScope, owner, declarations);
new DeclarationResolver(context).process(); new DeclarationResolver(context).process();
new DelegationResolver(context).process(); new DelegationResolver(context).process();
new OverrideResolver(context).process(); new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies(); new BodyResolver(context).resolveBehaviorDeclarationBodies();
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process(); 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( public static void processStandardLibraryNamespace(
@NotNull JetSemanticServices semanticServices, @NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) { @NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace); TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.<PsiFile>alwaysTrue());
context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope()); context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope());
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace); context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
context.getDeclaringScopes().put(namespace, outerScope); context.getDeclaringScopes().put(namespace, outerScope);
@@ -104,7 +118,7 @@ public class TopDownAnalyzer {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) { public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
return ClassObjectStatus.NOT_ALLOWED; return ClassObjectStatus.NOT_ALLOWED;
} }
}, Collections.<JetDeclaration>singletonList(object), JetControlFlowDataTraceFactory.EMPTY, true); }, Collections.<JetDeclaration>singletonList(object), Predicates.equalTo(object.getContainingFile()), JetControlFlowDataTraceFactory.EMPTY, true);
} }
} }
@@ -26,7 +26,7 @@ public class TraceBasedRedeclarationHandler implements RedeclarationHandler {
private void report(DeclarationDescriptor first) { private void report(DeclarationDescriptor first) {
PsiElement firstElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, first); PsiElement firstElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, first);
if (firstElement != null) { if (firstElement != null) {
trace.report(REDECLARATION.on(firstElement)); trace.report(REDECLARATION.on(firstElement, first.getName()));
} }
else { else {
trace.report(REDECLARATION.on(first, trace.getBindingContext())); trace.report(REDECLARATION.on(first, trace.getBindingContext()));
@@ -36,7 +36,7 @@ public class TypeHierarchyResolver {
this.context = context; this.context = context;
} }
public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List<? extends JetDeclaration> declarations) { public void process(@NotNull JetScope outerScope, @NotNull NamespaceLike owner, @NotNull Collection<? extends JetDeclaration> declarations) {
collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes
processTypeImports(); processTypeImports();
@@ -387,13 +387,15 @@ public class CallResolver {
ResolvedValueArgument valueArgument = entry.getValue(); ResolvedValueArgument valueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = entry.getKey(); ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor);
for (JetExpression expression : valueArgument.getArgumentExpressions()) { for (JetExpression expression : valueArgument.getArgumentExpressions()) {
// JetExpression expression = valueArgument.getArgumentExpression(); // JetExpression expression = valueArgument.getArgumentExpression();
// TODO : more attempts, with different expected types // TODO : more attempts, with different expected types
ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace); ExpressionTypingServices temporaryServices = new ExpressionTypingServices(semanticServices, temporaryTrace);
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE); JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
if (type != null) { if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
} }
else { else {
candidateCall.argumentHasNoType(); candidateCall.argumentHasNoType();
@@ -512,6 +514,14 @@ public class CallResolver {
return results; 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) { private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
if (receiver instanceof AutoCastReceiver) { if (receiver instanceof AutoCastReceiver) {
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
@@ -606,7 +616,7 @@ public class CallResolver {
ValueParameterDescriptor parameterDescriptor = entry.getKey(); ValueParameterDescriptor parameterDescriptor = entry.getKey();
ResolvedValueArgument resolvedArgument = entry.getValue(); ResolvedValueArgument resolvedArgument = entry.getValue();
JetType parameterType = parameterDescriptor.getOutType(); JetType parameterType = getEffectiveExpectedType(parameterDescriptor);
List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions(); List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions();
for (JetExpression argumentExpression : argumentExpressions) { for (JetExpression argumentExpression : argumentExpressions) {
@@ -84,7 +84,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
} }
else if (!valueParameters.isEmpty()) { else if (!valueParameters.isEmpty()) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.isVararg()) { if (valueParameterDescriptor.getVarargElementType() != null) {
put(candidateCall, valueParameterDescriptor, valueArgument, varargs); put(candidateCall, valueParameterDescriptor, valueArgument, varargs);
usedParameters.add(valueParameterDescriptor); usedParameters.add(valueParameterDescriptor);
} }
@@ -123,7 +123,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
} }
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1); 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.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list");
temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); temporaryTrace.report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral));
error = true; error = true;
@@ -154,7 +154,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
if (valueParameter.hasDefaultValue()) { if (valueParameter.hasDefaultValue()) {
candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT); candidateCall.recordValueArgument(valueParameter, DefaultValueArgument.DEFAULT);
} }
else if (valueParameter.isVararg()) { else if (valueParameter.getVarargElementType() != null) {
candidateCall.recordValueArgument(valueParameter, new VarargValueArgument()); candidateCall.recordValueArgument(valueParameter, new VarargValueArgument());
} }
else { else {
@@ -182,7 +182,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
} }
private static <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) { private static <D extends CallableDescriptor> void put(ResolvedCallImpl<D> candidateCall, ValueParameterDescriptor valueParameterDescriptor, ValueArgument valueArgument, Map<ValueParameterDescriptor, VarargValueArgument> varargs) {
if (valueParameterDescriptor.isVararg()) { if (valueParameterDescriptor.getVarargElementType() != null) {
VarargValueArgument vararg = varargs.get(valueParameterDescriptor); VarargValueArgument vararg = varargs.get(valueParameterDescriptor);
if (vararg == null) { if (vararg == null) {
vararg = new VarargValueArgument(); vararg = new VarargValueArgument();
@@ -147,7 +147,7 @@ public class ErrorUtils {
ERROR_PARAMETER_TYPE, ERROR_PARAMETER_TYPE,
ERROR_PARAMETER_TYPE, ERROR_PARAMETER_TYPE,
false, false,
false)); null));
} }
return result; return result;
} }
@@ -378,7 +378,7 @@ public class JetStandardClasses {
List<ValueParameterDescriptor> valueParameters = Lists.newArrayList(); List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
for (int i = first; i <= last; i++) { for (int i = first; i <= last; i++) {
JetType parameterType = arguments.get(i).getType(); JetType parameterType = arguments.get(i).getType();
ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, false); ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.<AnnotationDescriptor>emptyList(), "p" + i, null, parameterType, false, null);
valueParameters.add(valueParameterDescriptor); valueParameters.add(valueParameterDescriptor);
} }
return valueParameters; return valueParameters;
@@ -316,8 +316,8 @@ public class JetStandardLibrary {
} }
@NotNull @NotNull
public JetType getArrayType(@NotNull Variance variance, @NotNull JetType argument) { public JetType getArrayType(@NotNull Variance projectionType, @NotNull JetType argument) {
List<TypeProjection> types = Collections.singletonList(new TypeProjection(variance, argument)); List<TypeProjection> types = Collections.singletonList(new TypeProjection(projectionType, argument));
return new JetTypeImpl( return new JetTypeImpl(
Collections.<AnnotationDescriptor>emptyList(), Collections.<AnnotationDescriptor>emptyList(),
getArray().getTypeConstructor(), getArray().getTypeConstructor(),
@@ -87,7 +87,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) { if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) {
ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0);
ValueParameterDescriptor it = new ValueParameterDescriptorImpl( ValueParameterDescriptor it = new ValueParameterDescriptorImpl(
functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg() functionDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType()
); );
valueParameterDescriptors.add(it); valueParameterDescriptors.add(it);
parameterTypes.add(it.getOutType()); parameterTypes.add(it.getOutType());
@@ -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<JetDeclaration> declarations) {
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction) declaration;
if ("main".equals(function.getName())) {
List<JetParameter> parameters = function.getValueParameters();
if (parameters.size() == 1) {
JetTypeReference reference = parameters.get(0).getTypeReference();
if (reference != null && reference.getText().equals("Array<String>")) { // TODO correct check
return true;
}
}
}
}
}
return false;
}
}
@@ -133,7 +133,7 @@ public class DescriptorRenderer implements Renderer {
@Override @Override
public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("value-parameter")).append(" "); builder.append(renderKeyword("value-parameter")).append(" ");
if (descriptor.isVararg()) { if (descriptor.getVarargElementType() != null) {
builder.append(renderKeyword("vararg")).append(" "); builder.append(renderKeyword("vararg")).append(" ");
} }
return super.visitValueParameterDescriptor(descriptor, builder); return super.visitValueParameterDescriptor(descriptor, builder);
@@ -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<String> = a
fun test() {
Arrays.asList(1, 2, 3)
Arrays.asList<Int>(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)
}
@@ -10,3 +10,14 @@ namespace b {
} }
} }
namespace c {
import d.X
val x : X = X()
}
namespace d {
class X() {
}
}
@@ -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<String>) {
val command : Foo? = null
when (command) {
.equals(null) => 1; // must be resolved
?.equals(null) => 1 // same here
}
}
@@ -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
// ...
}
}
@@ -0,0 +1,7 @@
// KT-26 Import namespaces defined in this file
namespace foo {
import bar.* // Must not be an error
}
namespace bar {}
@@ -0,0 +1,10 @@
// KT-26 Import namespaces defined in this file
import html.* // Must not be an error
namespace html {
abstract class Factory<T> {
fun create() : T? = null
}
}
@@ -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 <!UNSAFE_INFIX_CALL!>+<!> 1
set + 1
1 <!UNSAFE_INFIX_CALL!>in<!> set
1 in 2
}
@@ -0,0 +1,4 @@
fun box() : String {
var a = 10
return if(a?.plus(10) == 20) "OK" else "fail"
}
+7 -3
View File
@@ -18,7 +18,8 @@ JetFile: Imports_ERR.jet
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name PsiErrorElement:Expecting qualified name
PsiElement(SEMICOLON)(';') <empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n') PsiWhiteSpace('\n')
IMPORT_DIRECTIVE IMPORT_DIRECTIVE
PsiElement(import)('import') PsiElement(import)('import')
@@ -27,7 +28,9 @@ JetFile: Imports_ERR.jet
PsiElement(DOT)('.') PsiElement(DOT)('.')
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name PsiErrorElement:Expecting qualified name
PsiElement(MUL)('*') <empty list>
PsiErrorElement:Expecting namespace or top level declaration
PsiElement(MUL)('*')
PsiWhiteSpace('\n') PsiWhiteSpace('\n')
IMPORT_DIRECTIVE IMPORT_DIRECTIVE
PsiElement(import)('import') PsiElement(import)('import')
@@ -37,7 +40,8 @@ JetFile: Imports_ERR.jet
PsiWhiteSpace(' ') PsiWhiteSpace(' ')
REFERENCE_EXPRESSION REFERENCE_EXPRESSION
PsiErrorElement:Expecting qualified name PsiErrorElement:Expecting qualified name
PsiElement(SEMICOLON)(';') <empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace('\n\n') PsiWhiteSpace('\n\n')
IMPORT_DIRECTIVE IMPORT_DIRECTIVE
PsiElement(import)('import') PsiElement(import)('import')
@@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.ImportingStrategy; import org.jetbrains.jet.lang.resolve.ImportingStrategy;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -80,7 +81,7 @@ public class CheckerTestUtilTest extends JetLiteFixture {
} }
public void test(PsiFile psiFile) { 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(); String expectedText = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList(); List<CheckerTestUtil.DiagnosedRange> diagnosedRanges = Lists.newArrayList();
@@ -42,7 +42,7 @@ public class FullJetPsiCheckerTest extends JetLiteFixture {
String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges); String clearText = CheckerTestUtil.parseDiagnosedRanges(expectedText, diagnosedRanges);
myFile = createPsiFile(myName, clearText); 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() { CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override @Override
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.ImportingStrategy; import org.jetbrains.jet.lang.resolve.ImportingStrategy;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import java.util.List; import java.util.List;
@@ -39,7 +40,7 @@ public class QuickJetPsiCheckerTest extends JetLiteFixture {
createAndCheckPsiFile(name, clearText); createAndCheckPsiFile(name, clearText);
JetFile jetFile = (JetFile) myFile; 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() { CheckerTestUtil.diagnosticsDiff(diagnosedRanges, bindingContext.getDiagnostics(), new CheckerTestUtil.DiagnosticDiffCallbacks() {
@Override @Override
@@ -88,7 +88,7 @@ public abstract class CodegenTestCase extends JetLiteFixture {
protected String blackBox() throws Exception { protected String blackBox() throws Exception {
ClassFileFactory codegens = generateClassesInFile(); ClassFileFactory codegens = generateClassesInFile();
CodegensClassLoader loader = new CodegensClassLoader(codegens); GeneratedClassLoader loader = new GeneratedClassLoader(codegens);
final JetNamespace namespace = myFile.getRootNamespace(); final JetNamespace namespace = myFile.getRootNamespace();
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", "."); String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", ".");
@@ -215,23 +215,4 @@ public abstract class CodegenTestCase extends JetLiteFixture {
return super.loadClass(name); 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);
}
}
} }
@@ -207,4 +207,9 @@ public class ControlStructuresTest extends CodegenTestCase {
public void testKt299() throws Exception { public void testKt299() throws Exception {
blackBoxFile("regressions/kt299.jet"); blackBoxFile("regressions/kt299.jet");
} }
public void testKt416() throws Exception {
blackBoxFile("regressions/kt416.jet");
System.out.println(generateToText());
}
} }
@@ -8,22 +8,55 @@ import java.lang.reflect.Method;
*/ */
public class VarArgTest extends CodegenTestCase { public class VarArgTest extends CodegenTestCase {
public void testStringArray () throws InvocationTargetException, IllegalAccessException { public void testStringArray () throws InvocationTargetException, IllegalAccessException {
/*
loadText("fun test(vararg ts: String) = ts"); loadText("fun test(vararg ts: String) = ts");
System.out.println(generateToText()); System.out.println(generateToText());
final Method main = generateFunction(); final Method main = generateFunction();
Object[] args = {"mama", "papa"}; String[] args = {"mama", "papa"};
assertTrue(args == main.invoke(null, args)); assertTrue(args == main.invoke(null, new Object[]{ args } ));
*/
} }
public void testIntArray () throws InvocationTargetException, IllegalAccessException { public void testIntArray () throws InvocationTargetException, IllegalAccessException {
/*
loadText("fun test(vararg ts: Int) = ts"); loadText("fun test(vararg ts: Int) = ts");
System.out.println(generateToText()); System.out.println(generateToText());
final Method main = generateFunction(); final Method main = generateFunction();
int[] args = {3, 4}; 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"));
} }
} }
@@ -44,7 +44,7 @@ public class JetDefaultModalityModifiersTest extends JetLiteFixture {
List<JetDeclaration> declarations = file.getRootNamespace().getDeclarations(); List<JetDeclaration> declarations = file.getRootNamespace().getDeclarations();
JetDeclaration aClass = declarations.get(0); JetDeclaration aClass = declarations.get(0);
assert aClass instanceof JetClass; 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); DeclarationDescriptor classDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, aClass);
WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING); WritableScopeImpl scope = new WritableScopeImpl(libraryScope, root, RedeclarationHandler.DO_NOTHING);
assert classDescriptor instanceof ClassifierDescriptor; assert classDescriptor instanceof ClassifierDescriptor;
+72
View File
@@ -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 were 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.
+7
View File
@@ -0,0 +1,7 @@
import kotlin.modules.ModuleSetBuilder
fun defineModules(builder: ModuleSetBuilder) {
builder.module("hello") {
source files "HelloNames.kt"
}
}
-1
View File
@@ -20,7 +20,6 @@
<orderEntry type="module" module-name="frontend" /> <orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" /> <orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" /> <orderEntry type="module" module-name="stdlib" />
<orderEntry type="module" module-name="cli" />
<orderEntry type="module" module-name="compiler-tests" /> <orderEntry type="module" module-name="compiler-tests" />
</component> </component>
</module> </module>
@@ -8,7 +8,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; 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; import org.jetbrains.jet.resolve.DescriptorRenderer;
/** /**
@@ -26,7 +26,7 @@ public class JetQuickDocumentationProvider extends AbstractDocumentationProvider
ref = PsiTreeUtil.getParentOfType(originalElement, JetReferenceExpression.class); ref = PsiTreeUtil.getParentOfType(originalElement, JetReferenceExpression.class);
} }
if (ref != null) { 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); DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, ref);
if (declarationDescriptor != null) { if (declarationDescriptor != null) {
return render(declarationDescriptor); return render(declarationDescriptor);
@@ -11,6 +11,7 @@ import org.jetbrains.jet.checkers.CheckerTestUtil;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.awt.*; import java.awt.*;
import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.Clipboard;
@@ -28,7 +29,7 @@ public class CopyAsDiagnosticTestAction extends AnAction {
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
assert editor != null && psiFile != null; assert editor != null && psiFile != null;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString(); String result = CheckerTestUtil.addDiagnosticMarkersToText(psiFile, bindingContext).toString();
@@ -12,9 +12,9 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.lang.types.JetType;
import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
/** /**
* @author yole * @author yole
@@ -26,7 +26,7 @@ public class ShowExpressionTypeAction extends AnAction {
PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE); PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
assert editor != null && psiFile != null; assert editor != null && psiFile != null;
JetExpression expression; JetExpression expression;
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache((JetFile) psiFile); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) psiFile);
if (editor.getSelectionModel().hasSelection()) { if (editor.getSelectionModel().hasSelection()) {
int startOffset = editor.getSelectionModel().getSelectionStart(); int startOffset = editor.getSelectionModel().getSelectionStart();
int endOffset = editor.getSelectionModel().getSelectionEnd(); int endOffset = editor.getSelectionModel().getSelectionEnd();
@@ -20,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetHighlighter; import org.jetbrains.jet.plugin.JetHighlighter;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
@@ -53,7 +54,7 @@ public class DebugInfoAnnotator implements Annotator {
if (element instanceof JetFile) { if (element instanceof JetFile) {
JetFile file = (JetFile) element; JetFile file = (JetFile) element;
try { try {
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final Set<JetReferenceExpression> unresolvedReferences = Sets.newHashSet(); final Set<JetReferenceExpression> unresolvedReferences = Sets.newHashSet();
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; 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 org.jetbrains.jet.resolve.DescriptorRenderer;
import javax.swing.*; import javax.swing.*;
@@ -45,7 +45,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
JetFile file = PsiTreeUtil.getParentOfType(element, JetFile.class); JetFile file = PsiTreeUtil.getParentOfType(element, JetFile.class);
if (file == null) return null; if (file == null) return null;
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
if (element instanceof JetClass) { if (element instanceof JetClass) {
JetClass jetClass = (JetClass) element; JetClass jetClass = (JetClass) element;
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetHighlighter; 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.JetIntentionActionFactory;
import org.jetbrains.jet.plugin.quickfix.QuickFixes; import org.jetbrains.jet.plugin.quickfix.QuickFixes;
@@ -54,12 +55,13 @@ public class JetPsiChecker implements Annotator {
JetFile file = (JetFile) element; JetFile file = (JetFile) element;
Project project = element.getProject(); Project project = element.getProject();
try { try {
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
if (errorReportingEnabled) { if (errorReportingEnabled) {
Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics());
Set<PsiElement> redeclarations = Sets.newHashSet(); Set<PsiElement> redeclarations = Sets.newHashSet();
for (Diagnostic diagnostic : diagnostics) { 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; Annotation annotation = null;
if (diagnostic.getSeverity() == Severity.ERROR) { if (diagnostic.getSeverity() == Severity.ERROR) {
if (diagnostic instanceof UnresolvedReferenceDiagnostic) { if (diagnostic instanceof UnresolvedReferenceDiagnostic) {
@@ -1,5 +1,6 @@
package org.jetbrains.jet.plugin.compiler; package org.jetbrains.jet.plugin.compiler;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.compiler.CompileContext;
@@ -66,16 +67,21 @@ public class JetCompiler implements TranslatingCompiler {
ApplicationManager.getApplication().runReadAction(new Runnable() { ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override @Override
public void run() { public void run() {
VirtualFile[] allFiles = compileContext.getCompileScope().getFiles(null, true);
GenerationState generationState = new GenerationState(compileContext.getProject(), false); GenerationState generationState = new GenerationState(compileContext.getProject(), false);
List<JetNamespace> namespaces = Lists.newArrayList(); List<JetNamespace> namespaces = Lists.newArrayList();
for (VirtualFile virtualFile : virtualFiles) { for (VirtualFile virtualFile : allFiles) {
PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile); PsiFile psiFile = PsiManager.getInstance(compileContext.getProject()).findFile(virtualFile);
if (psiFile instanceof JetFile) { if (psiFile instanceof JetFile) {
namespaces.add(((JetFile) psiFile).getRootNamespace()); 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.<PsiFile>alwaysTrue(),
JetControlFlowDataTraceFactory.EMPTY);
boolean errors = false; boolean errors = false;
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) { for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
@@ -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<JetFile, Collection<JetDeclaration>> WHOLE_PROJECT_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetDeclaration>>() {
@Override
public Collection<JetDeclaration> fun(final JetFile rootFile) {
final Project project = rootFile.getProject();
final Set<JetDeclaration> 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);
}
}
@@ -21,8 +21,8 @@ import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.lang.types.JetStandardLibrary;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import java.util.*; import java.util.*;
@@ -125,7 +125,7 @@ public class JetPositionManager implements PositionManager {
if (mapper != null) { if (mapper != null) {
return mapper; return mapper;
} }
final BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(myDebugProcess.getProject()); final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(myDebugProcess.getProject());
final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext); final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext);
file.acceptChildren(new JetVisitorVoid() { file.acceptChildren(new JetVisitorVoid() {
@@ -12,7 +12,7 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl; 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; import java.util.Collection;
@@ -76,7 +76,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
protected PsiElement doResolve() { protected PsiElement doResolve() {
JetFile file = (JetFile) getElement().getContainingFile(); JetFile file = (JetFile) getElement().getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, myExpression); PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, myExpression);
if (psiElement != null) { if (psiElement != null) {
return psiElement; return psiElement;
@@ -88,7 +88,7 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
protected ResolveResult[] doMultiResolve() { protected ResolveResult[] doMultiResolve() {
JetFile file = (JetFile) getElement().getContainingFile(); JetFile file = (JetFile) getElement().getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression); Collection<? extends ResolvedCallImpl<? extends DeclarationDescriptor>> resolvedCalls = bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, myExpression);
if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY; if (resolvedCalls == null) return ResolveResult.EMPTY_ARRAY;
ResolveResult[] results = new ResolveResult[resolvedCalls.size()]; ResolveResult[] results = new ResolveResult[resolvedCalls.size()];
@@ -13,9 +13,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.List; import java.util.List;
@@ -51,7 +51,7 @@ class JetSimpleNameReference extends JetPsiReference {
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent; JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
JetFile file = (JetFile) myExpression.getContainingFile(); JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiverExpression); final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null) { if (expressionType != null) {
return collectLookupElements(bindingContext, expressionType.getMemberScope()); return collectLookupElements(bindingContext, expressionType.getMemberScope());
@@ -59,7 +59,7 @@ class JetSimpleNameReference extends JetPsiReference {
} }
else { else {
JetFile file = (JetFile) myExpression.getContainingFile(); JetFile file = (JetFile) myExpression.getContainingFile();
BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file); BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, myExpression); JetScope resolutionScope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, myExpression);
if (resolutionScope != null) { if (resolutionScope != null) {
return collectLookupElements(bindingContext, resolutionScope); return collectLookupElements(bindingContext, resolutionScope);
@@ -8,9 +8,12 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.psi.*; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.psi.JetClass;
import java.util.List; 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 * @author yole
@@ -22,6 +25,17 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
super(JetRunConfigurationType.getInstance()); 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 @Override
public PsiElement getSourceElement() { public PsiElement getSourceElement() {
return mySourceElement; return mySourceElement;
@@ -30,14 +44,14 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
@Override @Override
protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext configurationContext) { protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext configurationContext) {
JetClass containingClass = (JetClass) location.getParentElement(JetClass.class); JetClass containingClass = (JetClass) location.getParentElement(JetClass.class);
if (containingClass != null && hasMain(containingClass.getDeclarations())) { if (containingClass != null && JetMainDetector.hasMain(containingClass.getDeclarations())) {
mySourceElement = containingClass; mySourceElement = containingClass;
return createConfigurationByQName(location.getModule(), configurationContext, containingClass.getFQName()); return createConfigurationByQName(location.getModule(), configurationContext, getFQName(containingClass));
} }
PsiFile psiFile = location.getPsiElement().getContainingFile(); PsiFile psiFile = location.getPsiElement().getContainingFile();
if (psiFile instanceof JetFile) { if (psiFile instanceof JetFile) {
JetNamespace namespace = ((JetFile) psiFile).getRootNamespace(); JetNamespace namespace = ((JetFile) psiFile).getRootNamespace();
if (hasMain(namespace.getDeclarations())) { if (JetMainDetector.hasMain(namespace.getDeclarations())) {
mySourceElement = namespace; mySourceElement = namespace;
return createConfigurationByQName(location.getModule(), configurationContext, namespace.getFQName() + ".namespace"); return createConfigurationByQName(location.getModule(), configurationContext, namespace.getFQName() + ".namespace");
} }
@@ -45,25 +59,6 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im
return null; return null;
} }
private boolean hasMain(List<JetDeclaration> declarations) {
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction) declaration;
if ("main".equals(function.getName())) {
List<JetParameter> parameters = function.getValueParameters();
if (parameters.size() == 1) {
JetTypeReference reference = parameters.get(0).getTypeReference();
if (reference != null && reference.getText().equals("Array<String>")) { // TODO correct check
return true;
}
}
}
}
}
return false;
}
private RunnerAndConfigurationSettings createConfigurationByQName(Module module, ConfigurationContext context, String fqName) { private RunnerAndConfigurationSettings createConfigurationByQName(Module module, ConfigurationContext context, String fqName) {
RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(module.getProject(), context); RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(module.getProject(), context);
JetRunConfiguration configuration = (JetRunConfiguration) settings.getConfiguration(); JetRunConfiguration configuration = (JetRunConfiguration) settings.getConfiguration();
+11 -3
View File
@@ -1,15 +1,20 @@
namespace kotlin.modules namespace kotlin
namespace modules {
import java.util.* import java.util.*
import jet.modules.* import jet.modules.*
class ModuleSetBuilder() { class ModuleSetBuilder(): IModuleSetBuilder {
val modules: ArrayList<ModuleBuilder> = ArrayList<ModuleBuilder>() val modules: ArrayList<IModuleBuilder?> = ArrayList<IModuleBuilder?>()
fun module(name: String, callback: fun ModuleBuilder.()) { fun module(name: String, callback: fun ModuleBuilder.()) {
val builder = ModuleBuilder(name) val builder = ModuleBuilder(name)
builder.callback() builder.callback()
modules.add(builder)
} }
override fun getModules(): List<IModuleBuilder?>? = modules
} }
class SourcesBuilder(val parent: ModuleBuilder) { class SourcesBuilder(val parent: ModuleBuilder) {
@@ -44,4 +49,7 @@ class ModuleBuilder(val name: String): IModuleBuilder {
override fun getSourceFiles(): List<String?>? = sourceFiles override fun getSourceFiles(): List<String?>? = sourceFiles
override fun getClasspathRoots(): List<String?>? = classpathRoots override fun getClasspathRoots(): List<String?>? = classpathRoots
override fun getModuleName(): String? = name
} }
}
@@ -6,6 +6,7 @@ import java.util.List;
* @author yole * @author yole
*/ */
public interface IModuleBuilder { public interface IModuleBuilder {
String getModuleName();
List<String> getSourceFiles(); List<String> getSourceFiles();
List<String> getClasspathRoots(); List<String> getClasspathRoots();
} }
@@ -0,0 +1,10 @@
package jet.modules;
import java.util.List;
/**
* @author yole
*/
public interface IModuleSetBuilder {
List<IModuleBuilder> getModules();
}