diff --git a/build.xml b/build.xml index 6c91c946fa5..c799c56523e 100644 --- a/build.xml +++ b/build.xml @@ -9,6 +9,11 @@ + + + + + @@ -26,9 +31,21 @@ - + + + + + + + + + + + + + @@ -49,7 +66,11 @@ - + + + + + diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java index d2ba73c02ef..669bda88f70 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -5,7 +5,9 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; import com.intellij.util.Function; import com.intellij.util.Processor; import jet.modules.IModuleBuilder; @@ -22,6 +24,8 @@ import java.io.*; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.jar.*; @@ -53,14 +57,18 @@ public class CompileEnvironment { } public boolean initializeKotlinRuntime() { + return initializeKotlinRuntime(myEnvironment); + } + + public static boolean initializeKotlinRuntime(JetCoreEnvironment environment) { final File unpackedRuntimePath = getUnpackedRuntimePath(); if (unpackedRuntimePath != null) { - myEnvironment.addToClasspath(unpackedRuntimePath); + environment.addToClasspath(unpackedRuntimePath); } else { final File runtimeJarPath = getRuntimeJarPath(); if (runtimeJarPath != null && runtimeJarPath.exists()) { - myEnvironment.addToClasspath(runtimeJarPath); + environment.addToClasspath(runtimeJarPath); } else { return false; @@ -147,7 +155,7 @@ public class CompileEnvironment { return null; } - public void compileModuleScript(String moduleFile) { + public void compileModuleScript(String moduleFile, String jarPath, boolean jarRuntime) { final IModuleSetBuilder moduleSetBuilder = loadModuleScript(moduleFile); if (moduleSetBuilder == null) { return; @@ -156,9 +164,9 @@ public class CompileEnvironment { final String directory = new File(moduleFile).getParent(); for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory); - final String path = new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); + final String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); try { - writeToJar(moduleFactory, new FileOutputStream(path), null, true); + writeToJar(moduleFactory, new FileOutputStream(path), null, jarRuntime); } catch (FileNotFoundException e) { throw new CompileEnvironmentException("Invalid jar path " + path, e); } @@ -168,25 +176,7 @@ public class CompileEnvironment { public IModuleSetBuilder loadModuleScript(String moduleFile) { CompileSession scriptCompileSession = new CompileSession(myEnvironment); scriptCompileSession.addSources(moduleFile); - - URL url = CompileEnvironment.class.getClassLoader().getResource("ModuleBuilder.kt"); - if (url != null) { - String path = url.getPath(); - if (path.startsWith("file:")) { - path = path.substring(5); - } - final VirtualFile vFile = myEnvironment.getJarFileSystem().findFileByPath(path); - if (vFile == null) { - throw new CompileEnvironmentException("Couldn't load ModuleBuilder.kt from runtime jar: "+ url); - } - scriptCompileSession.addSources(vFile); - } - else { - // building from source - final String homeDirectory = getHomeDirectory(); - final File file = new File(homeDirectory, "stdlib/ktSrc/ModuleBuilder.kt"); - scriptCompileSession.addSources(myEnvironment.getLocalFileSystem().findFileByPath(file.getPath())); - } + scriptCompileSession.addStdLibSources(); if (!scriptCompileSession.analyze(myErrorStream)) { return null; @@ -223,6 +213,7 @@ public class CompileEnvironment { public ClassFileFactory compileModule(IModuleBuilder moduleBuilder, String directory) { CompileSession moduleCompileSession = new CompileSession(myEnvironment); + moduleCompileSession.addStdLibSources(); for (String sourceFile : moduleBuilder.getSourceFiles()) { moduleCompileSession.addSources(new File(directory, sourceFile).getPath()); } @@ -239,6 +230,17 @@ public class CompileEnvironment { return new File(PathManager.getResourceRoot(CompileEnvironment.class, "/org/jetbrains/jet/compiler/CompileEnvironment.class")).getParentFile().getParentFile().getParent(); } + private static final List sanitized = Arrays.asList("kotlin/", "std/"); + public static boolean skipFile(String name) { + boolean skip = false; + for (String prefix : sanitized) { + if(name.startsWith(prefix)) { + return true; + } + } + return false; + } + public static void writeToJar(ClassFileFactory factory, final OutputStream fos, @Nullable String mainClass, boolean includeRuntime) { try { Manifest manifest = new Manifest(); @@ -251,8 +253,10 @@ public class CompileEnvironment { JarOutputStream stream = new JarOutputStream(fos, manifest); try { for (String file : factory.files()) { - stream.putNextEntry(new JarEntry(file)); - stream.write(factory.asBytes(file)); + if(!skipFile(file)) { + stream.putNextEntry(new JarEntry(file)); + stream.write(factory.asBytes(file)); + } } if (includeRuntime) { writeRuntimeToJar(stream); @@ -316,9 +320,10 @@ public class CompileEnvironment { } } - public void compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir) { + public void compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) { CompileSession session = new CompileSession(myEnvironment); session.addSources(sourceFileOrDir); + session.addStdLibSources(); String mainClass = null; for (JetNamespace namespace : session.getSourceFileNamespaces()) { @@ -334,7 +339,7 @@ public class CompileEnvironment { ClassFileFactory factory = session.generate(); if (jar != null) { try { - writeToJar(factory, new FileOutputStream(jar), mainClass, true); + writeToJar(factory, new FileOutputStream(jar), mainClass, includeRuntime); } catch (FileNotFoundException e) { throw new CompileEnvironmentException("Invalid jar path " + jar, e); } @@ -350,13 +355,14 @@ public class CompileEnvironment { private static void writeToOutputDirectory(ClassFileFactory factory, final String outputDir) { List files = factory.files(); for (String file : files) { - File target = new File(outputDir, file); - try { - FileUtil.writeToFile(target, factory.asBytes(file)); - } catch (IOException e) { - throw new CompileEnvironmentException(e); + if(!skipFile(file)) { + File target = new File(outputDir, file); + try { + FileUtil.writeToFile(target, factory.asBytes(file)); + } catch (IOException e) { + throw new CompileEnvironmentException(e); + } } } } - } diff --git a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java index e90fda9eb8a..91a0dccaf9e 100644 --- a/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java +++ b/compiler/backend/src/org/jetbrains/jet/compiler/CompileSession.java @@ -16,6 +16,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.java.JavaDefaultImports; import org.jetbrains.jet.plugin.JetFileType; +import java.io.File; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; @@ -47,7 +48,22 @@ public class CompileSession { return; } - addSources(vFile); + addSources(new File(path)); + } + + private void addSources(File file) { + if(file.isDirectory()) { + for (File child : file.listFiles()) { + addSources(child); + } + } + else { + VirtualFile fileByPath = myEnvironment.getLocalFileSystem().findFileByPath(file.getAbsolutePath()); + PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(fileByPath); + if(psiFile instanceof JetFile) { + mySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace()); + } + } } public void addSources(VirtualFile vFile) { @@ -66,13 +82,6 @@ public class CompileSession { } } - public void addLibrarySources(VirtualFile vFile) { - PsiFile psiFile = PsiManager.getInstance(myEnvironment.getProject()).findFile(vFile); - if (psiFile instanceof JetFile) { - myLibrarySourceFileNamespaces.add(((JetFile) psiFile).getRootNamespace()); - } - } - public List getSourceFileNamespaces() { return mySourceFileNamespaces; } @@ -104,4 +113,22 @@ public class CompileSession { generationState.compileCorrectNamespaces(myBindingContext, mySourceFileNamespaces); return generationState.createText(); } + + public boolean addStdLibSources() { + final File unpackedRuntimePath = CompileEnvironment.getUnpackedRuntimePath(); + if (unpackedRuntimePath != null) { + addSources(new File(unpackedRuntimePath, "../../../stdlib/ktSrc").getAbsoluteFile()); + } + else { + final File runtimeJarPath = CompileEnvironment.getRuntimeJarPath(); + if (runtimeJarPath != null && runtimeJarPath.exists()) { + // todo + throw new UnsupportedOperationException("Loading of stdlib sources from jar"); + } + else { + return false; + } + } + return true; + } } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java index 00b8cb1e85b..56db85a522d 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/KotlinCompiler.java @@ -23,6 +23,8 @@ public class KotlinCompiler { public String src; @Argument(value = "module", description = "module to compile") public String module; + @Argument(value = "includeRuntime", description = "include Kotlin runtime in to resulting jar") + public boolean includeRuntime; } public static void main(String[] args) { @@ -32,7 +34,7 @@ public class KotlinCompiler { Args.parse(arguments, args); } catch (Throwable t) { - System.out.println("Usage: KotlinCompiler [-output |-jar ] -src "); + System.out.println("Usage: KotlinCompiler [-output |-jar ] [-src |-module ] [-includeRuntime]"); t.printStackTrace(); return; } @@ -47,11 +49,11 @@ public class KotlinCompiler { } if (arguments.module != null) { - environment.compileModuleScript(arguments.module); + environment.compileModuleScript(arguments.module, arguments.jar, arguments.includeRuntime); return; } else { - environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir); + environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime); } } catch (CompileEnvironmentException e) { System.out.println(e.getMessage()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 2ea2a103180..fc8ce9013f2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -44,7 +44,10 @@ public interface Errors { } }; UnresolvedReferenceDiagnosticFactory UNRESOLVED_REFERENCE = new UnresolvedReferenceDiagnosticFactory("Unresolved reference"); - RedeclarationDiagnosticFactory REDECLARATION = RedeclarationDiagnosticFactory.INSTANCE; + + RedeclarationDiagnosticFactory REDECLARATION = RedeclarationDiagnosticFactory.REDECLARATION; + RedeclarationDiagnosticFactory NAME_SHADOWING = RedeclarationDiagnosticFactory.NAME_SHADOWING; + PsiElementOnlyDiagnosticFactory2 TYPE_MISMATCH = PsiElementOnlyDiagnosticFactory2.create(ERROR, "Type mismatch: inferred type is {1} but {0} was expected"); ParameterizedDiagnosticFactory1> INCOMPATIBLE_MODIFIERS = new ParameterizedDiagnosticFactory1>(ERROR, "Incompatible modifiers: ''{0}''") { @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java index 3a8c2f02733..648c8bfe5d2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/RedeclarationDiagnostic.java @@ -15,8 +15,8 @@ import static org.jetbrains.jet.lang.diagnostics.Severity.ERROR; public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement { public class SimpleRedeclarationDiagnostic extends DiagnosticWithPsiElementImpl implements RedeclarationDiagnostic { - public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement, @NotNull String name) { - super(RedeclarationDiagnosticFactory.INSTANCE, ERROR, "Redeclaration: " + name, psiElement); + public SimpleRedeclarationDiagnostic(@NotNull PsiElement psiElement, @NotNull String name, RedeclarationDiagnosticFactory factory) { + super(factory, factory.severity, factory.makeMessage(name), psiElement); } } @@ -24,11 +24,13 @@ public interface RedeclarationDiagnostic extends DiagnosticWithPsiElement operations = new HashSet(); Precedence[] values = Precedence.values(); @@ -272,7 +275,7 @@ public class JetExpressionParsing extends AbstractJetParsing { precedence.parseHigherPrecedence(this); - while (!myBuilder.newlineBeforeCurrentToken() && atSet(precedence.getOperations())) { + while (!interruptedWithNewLine() && atSet(precedence.getOperations())) { IElementType operation = tt(); parseOperationReference(); @@ -328,7 +331,7 @@ public class JetExpressionParsing extends AbstractJetParsing { PsiBuilder.Marker expression = mark(); parseAtomicExpression(); while (true) { - if (myBuilder.newlineBeforeCurrentToken()) { + if (interruptedWithNewLine()) { break; } else if (at(LBRACKET)) { @@ -1704,4 +1707,8 @@ public class JetExpressionParsing extends AbstractJetParsing { protected JetParsing create(SemanticWhitespaceAwarePsiBuilder builder) { return myJetParsing.create(builder); } + + private boolean interruptedWithNewLine() { + return !ALLOW_NEWLINE_OPERATIONS.contains(tt()) && myBuilder.newlineBeforeCurrentToken(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 9a97153ce8d..814752f7eaa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -124,9 +124,11 @@ public class JetParsing extends AbstractJetParsing { parseNamespaceName(); if (at(LBRACE)) { + // Because it's blocked namespace and it will be parsed as one of top level objects firstEntry.rollbackTo(); return; } + firstEntry.drop(); consumeIf(SEMICOLON); @@ -134,6 +136,7 @@ public class JetParsing extends AbstractJetParsing { firstEntry.rollbackTo(); } + // TODO: Duplicate with parsing imports in parseToplevelDeclarations while (at(IMPORT_KEYWORD)) { parseImportDirective(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java index e211deb85f4..68ecfaafd88 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/SemanticWhitespaceAwarePsiBuilderImpl.java @@ -26,26 +26,36 @@ public class SemanticWhitespaceAwarePsiBuilderImpl extends PsiBuilderAdapter imp @Override public boolean newlineBeforeCurrentToken() { if (!newlinesEnabled.peek()) return false; + if (eof()) return true; + // TODO: maybe, memoize this somehow? for (int i = 1; i <= getCurrentOffset(); i++) { IElementType previousToken = rawLookup(-i); + if (previousToken == JetTokens.BLOCK_COMMENT || previousToken == JetTokens.DOC_COMMENT || previousToken == JetTokens.EOL_COMMENT) { continue; } + if (previousToken != TokenType.WHITE_SPACE) { break; } + int previousTokenStart = rawTokenTypeStart(-i); int previousTokenEnd = rawTokenTypeStart(-i + 1); + assert previousTokenStart >= 0; assert previousTokenEnd < getOriginalText().length(); + for (int j = previousTokenStart; j < previousTokenEnd; j++) { - if (getOriginalText().charAt(j) == '\n') return true; + if (getOriginalText().charAt(j) == '\n') { + return true; + } } } + return false; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index ba492a83cde..c66af6e8f03 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -123,4 +123,35 @@ public class DescriptorUtils { } return NO_RECEIVER; } + + /** + * The primary case for local extensions is the following: + * + * I had a locally declared extension function or a local variable of function type called foo + * And I called it on my x + * Now, someone added function foo() to the class of x + * My code should not change + * + * thus + * + * local extension prevail over members (and members prevail over all non-local extensions) + */ + public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { + if (candidate instanceof ValueParameterDescriptor) { + return true; + } + DeclarationDescriptor parent = candidate.getContainingDeclaration(); + if (!(parent instanceof FunctionDescriptor)) { + return false; + } + FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; + DeclarationDescriptor current = containerOfTheCurrentLocality; + while (current != null) { + if (current == functionDescriptor) { + return true; + } + current = current.getContainingDeclaration(); + } + return false; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index 872781fb28b..823666d4ed2 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -5,12 +5,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSuperExpression; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastService; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; @@ -36,7 +35,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor Collection> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection> local, Collection> nonlocal) { for (ResolvedCallImpl resolvedCall : allDescriptors) { - if (isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) { + if (DescriptorUtils.isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) { local.add(resolvedCall); } else { @@ -45,37 +44,6 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor } } - /** - * The primary case for local extensions is the following: - * - * I had a locally declared extension function or a local variable of function type called foo - * And I called it on my x - * Now, someone added function foo() to the class of x - * My code should not change - * - * thus - * - * local extension prevail over members (and members prevail over all non-local extensions) - */ - private static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { - if (candidate instanceof ValueParameterDescriptor) { - return true; - } - DeclarationDescriptor parent = candidate.getContainingDeclaration(); - if (!(parent instanceof FunctionDescriptor)) { - return false; - } - FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent; - DeclarationDescriptor current = containerOfTheCurrentLocality; - while (current != null) { - if (current == functionDescriptor) { - return true; - } - current = current.getContainingDeclaration(); - } - return false; - } - @Nullable /*package*/ static JetSuperExpression getReceiverSuper(@NotNull ReceiverDescriptor receiver) { if (receiver instanceof ExpressionReceiver) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 381d52bdf91..f573e39e79a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -6,10 +6,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.calls.TaskPrioritizers; +import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; @@ -209,6 +213,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } variableDescriptor = context.getDescriptorResolver().resolveLocalVariableDescriptor(context.scope.getContainingDeclaration(), loopParameter, expectedParameterType); } + + { + // http://youtrack.jetbrains.net/issue/KT-527 + + VariableDescriptor olderVariable = context.scope.getVariable(variableDescriptor.getName()); + if (olderVariable != null && DescriptorUtils.isLocal(context.scope.getContainingDeclaration(), olderVariable)) { + context.trace.report(Errors.NAME_SHADOWING.on(variableDescriptor, context.trace.getBindingContext())); + } + } + loopScope.addVariableDescriptor(variableDescriptor); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 8c2c8a5da04..59642c4c73e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; import org.jetbrains.jet.lang.resolve.calls.CallMaker; @@ -91,6 +92,13 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetType outType = propertyDescriptor.getOutType(); JetType initializerType = facade.getType(initializer, context.replaceExpectedType(outType).replaceScope(scope)); } + + { + VariableDescriptor olderVariable = scope.getVariable(propertyDescriptor.getName()); + if (olderVariable != null && DescriptorUtils.isLocal(propertyDescriptor.getContainingDeclaration(), olderVariable)) { + context.trace.report(Errors.NAME_SHADOWING.on(propertyDescriptor, context.trace.getBindingContext())); + } + } scope.addVariableDescriptor(propertyDescriptor); return checkExpectedType(property, context); diff --git a/compiler/testData/checkerWithErrorTypes/quick/control/ForWithoutBraces.jet b/compiler/testData/checkerWithErrorTypes/quick/control/ForWithoutBraces.jet new file mode 100644 index 00000000000..d79dd7e77e0 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/control/ForWithoutBraces.jet @@ -0,0 +1,8 @@ +// http://youtrack.jetbrains.net/issue/KT-552 +// KT-552 For variable unresolved if loop body is not block + +fun ff() { + var i = 1 + for (j in 1..10) + i += j +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet new file mode 100644 index 00000000000..7cac265e866 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt337.jet @@ -0,0 +1,14 @@ +//KT-337 Can't break a line before a dot + +class A() { + fun foo() {} +} + +fun test() { + val a = A() + + a + + .foo() // Should be a valid expression + +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInFunctionBody.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInFunctionBody.jet new file mode 100644 index 00000000000..3f99c1e45bb --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInFunctionBody.jet @@ -0,0 +1,5 @@ + +fun f(p: Int): Int { + val p = 2 + return p +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInNestedBlockInFor.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInNestedBlockInFor.jet new file mode 100644 index 00000000000..e3e91fbe857 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowParameterInNestedBlockInFor.jet @@ -0,0 +1,7 @@ +fun f(i: Int) { + for (j in 1..100) { + { + var i = 12 + } + } +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInClosure.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInClosure.jet new file mode 100644 index 00000000000..c785e3f5fc7 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInClosure.jet @@ -0,0 +1,3 @@ +val i = 17 + +val f = { (): Int => var i = 17; i } diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFor.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFor.jet new file mode 100644 index 00000000000..e0d4766e89f --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFor.jet @@ -0,0 +1,11 @@ +class RedefinePropertyInFor() { + + var i = 1 + + fun ff() { + for (i in 0..10) { + } + } + +} + diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFunction.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFunction.jet new file mode 100644 index 00000000000..cacf415e65e --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowPropertyInFunction.jet @@ -0,0 +1,10 @@ +class RedefinePropertyInFunction() { + + var i = 17 + + fun f(): Int { + var i = 18 + return i + } + +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInFor.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInFor.jet new file mode 100644 index 00000000000..b62b6d0ea30 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInFor.jet @@ -0,0 +1,6 @@ +fun ff(): Int { + var i = 1 + for (i in 0..10) { + } + return i +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedBlock.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedBlock.jet new file mode 100644 index 00000000000..2fd755bdc1c --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedBlock.jet @@ -0,0 +1,7 @@ +fun ff(): Int { + var i = 1 + { + val i = 2 + } + return i +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosure.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosure.jet new file mode 100644 index 00000000000..d9dd9110893 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosure.jet @@ -0,0 +1,5 @@ +fun f(): Int { + var i = 17 + { (): Unit => var i = 18 } + return i +} diff --git a/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosureParam.jet b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosureParam.jet new file mode 100644 index 00000000000..6ba5fd4c919 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/shadowing/ShadowVariableInNestedClosureParam.jet @@ -0,0 +1,5 @@ +fun ff(): Int { + var i = 1 + { (i: Int) => i } + return i +} diff --git a/compiler/testData/codegen/regressions/kt640.jet b/compiler/testData/codegen/regressions/kt640.jet new file mode 100644 index 00000000000..705fc1f338c --- /dev/null +++ b/compiler/testData/codegen/regressions/kt640.jet @@ -0,0 +1,29 @@ +namespace demo + +public open class Identifier(myName : T?, myHasDollar : Boolean) { + { + $myName = myName + $myHasDollar = myHasDollar + } + + private val myName : T? + private var myHasDollar : Boolean + private var myNullable : Boolean = true + + open public fun getName() : T? { + return myName + } + + class object { + open public fun init(name : T?) : Identifier { + val __ = Identifier(name, false) + return __ + } + } +} + +fun box() : String { + var i3 : Identifier<*>? = Identifier.init("name") + System.out?.println("Hello, " + i3?.getName()) + return "OK" +} diff --git a/compiler/testData/compiler/smoke/Smoke.kt b/compiler/testData/compiler/smoke/Smoke.kt index 6da801d1fde..d41ccce56b7 100644 --- a/compiler/testData/compiler/smoke/Smoke.kt +++ b/compiler/testData/compiler/smoke/Smoke.kt @@ -1,4 +1,7 @@ namespace Smoke +import std.io.* + fun main(args: Array) { + print(args) } diff --git a/compiler/testData/psi/NewLinesValidOperations.jet b/compiler/testData/psi/NewLinesValidOperations.jet new file mode 100644 index 00000000000..1a9483d7f62 --- /dev/null +++ b/compiler/testData/psi/NewLinesValidOperations.jet @@ -0,0 +1,11 @@ +fun test() { + val str = "" + + str + + .length + + str + + ?.length +} \ No newline at end of file diff --git a/compiler/testData/psi/NewLinesValidOperations.txt b/compiler/testData/psi/NewLinesValidOperations.txt new file mode 100644 index 00000000000..22e86010779 --- /dev/null +++ b/compiler/testData/psi/NewLinesValidOperations.txt @@ -0,0 +1,41 @@ +JetFile: NewLinesValidOperations.jet + NAMESPACE + FUN + PsiElement(fun)('fun') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('test') + VALUE_PARAMETER_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement(LBRACE)('{') + PsiWhiteSpace('\n ') + PROPERTY + PsiElement(val)('val') + PsiWhiteSpace(' ') + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace(' ') + PsiElement(EQ)('=') + PsiWhiteSpace(' ') + STRING_TEMPLATE + PsiElement(OPEN_QUOTE)('"') + PsiElement(CLOSING_QUOTE)('"') + PsiWhiteSpace('\n\n ') + DOT_QUALIFIED_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace('\n\n ') + PsiElement(DOT)('.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('length') + PsiWhiteSpace('\n\n ') + SAFE_ACCESS_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('str') + PsiWhiteSpace('\n\n ') + PsiElement(SAFE_ACCESS)('?.') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('length') + PsiWhiteSpace('\n') + PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/compiler/tests/compiler-tests.iml b/compiler/tests/compiler-tests.iml index d1dadb8a16b..05bb0565855 100644 --- a/compiler/tests/compiler-tests.iml +++ b/compiler/tests/compiler-tests.iml @@ -11,6 +11,7 @@ + diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index 485a97b80d2..09f1485d650 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -1,6 +1,10 @@ package org.jetbrains.jet.codegen; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetLiteFixture; import org.jetbrains.jet.lang.psi.JetFile; @@ -9,6 +13,8 @@ import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.parsing.JetParsingTest; import org.junit.Assert; +import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java index 05c5a66ca93..d8eb251833e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ObjectGenTest.java @@ -25,4 +25,8 @@ public class ObjectGenTest extends CodegenTestCase { public void testKt560() throws Exception { blackBoxFile("regressions/kt560.jet"); } + + public void testKt640() throws Exception { + blackBoxFile("regressions/kt640.jet"); + } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index 7337274caac..cd1bb67e1c3 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -6,6 +6,7 @@ import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.CompileSession; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; @@ -30,8 +31,8 @@ public class StdlibTest extends CodegenTestCase { session.addSources(myFile.getVirtualFile()); try { - session.addSources(addStdLib()); - } catch (IOException e) { + session.addStdLibSources(); + } catch (Throwable e) { throw new RuntimeException(e); } @@ -45,9 +46,9 @@ public class StdlibTest extends CodegenTestCase { protected ClassFileFactory generateClassesInFile() { try { CompileSession session = new CompileSession(myEnvironment); - + CompileEnvironment.initializeKotlinRuntime(myEnvironment); session.addSources(myFile.getVirtualFile()); - session.addSources(addStdLib()); + session.addStdLibSources(); if (!session.analyze(System.out)) { return null; @@ -57,18 +58,11 @@ public class StdlibTest extends CodegenTestCase { } catch (RuntimeException e) { System.out.println(generateToText()); throw e; - } catch (IOException e) { + } catch (Throwable e) { throw new RuntimeException(e); } } - private VirtualFile addStdLib() throws IOException { - String text = FileUtil.loadFile(new File(JetParsingTest.getTestDataDir() + "/../../stdlib/ktSrc/StandardLibrary.kt"), CharsetToolkit.UTF8).trim(); - text = StringUtil.convertLineSeparators(text); - PsiFile stdLibFile = createFile("StandardLibrary.kt", text); - return stdLibFile.getVirtualFile(); - } - public void testInputStreamIterator () { blackBoxFile("inputStreamIterator.jet"); // System.out.println(generateToText()); @@ -85,4 +79,16 @@ public class StdlibTest extends CodegenTestCase { public void testKt528 () { blackBoxFile("regressions/kt528.kt"); } + + public void testCollectionSize () throws Exception { + loadText("import std.util.*; fun box() = if(java.util.Arrays.asList(0, 1, 2)?.size == 3) \"OK\" else \"fail\""); +// System.out.println(generateToText()); + blackBox(); + } + + public void testCollectionEmpty () throws Exception { + loadText("import std.util.*; fun box() = if(java.util.Arrays.asList(0, 1, 2)?.empty ?: false) \"OK\" else \"fail\""); +// System.out.println(generateToText()); + blackBox(); + } } diff --git a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java index 4b01efe9efd..520dee18d48 100644 --- a/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java +++ b/compiler/tests/org/jetbrains/jet/compiler/CompileEnvironmentTest.java @@ -3,20 +3,20 @@ package org.jetbrains.jet.compiler; import jet.modules.IModuleBuilder; import jet.modules.IModuleSetBuilder; import junit.framework.TestCase; +import org.jetbrains.jet.cli.KotlinCompiler; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.parsing.JetParsingTest; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; /** * @author yole + * @author alex.tkachman */ public class CompileEnvironmentTest extends TestCase { private CompileEnvironment environment; @@ -51,7 +51,58 @@ public class CompileEnvironmentTest extends TestCase { assertTrue(entries.contains("Smoke/namespace.class")); } - private List listEntries(JarInputStream is) throws IOException { + public void testSmokeWithCompilerJar() throws IOException { + File tempFile = File.createTempFile("compilerTest", "compilerTest"); + try { + KotlinCompiler.main(Arrays.asList("-module", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kts", "-jar", tempFile.getAbsolutePath()).toArray(new String[0])); + FileInputStream fileInputStream = new FileInputStream(tempFile); + try { + JarInputStream is = new JarInputStream(fileInputStream); + try { + final List entries = listEntries(is); + assertTrue(entries.contains("Smoke/namespace.class")); + assertEquals(1, entries.size()); + } + finally { + is.close(); + } + } + finally { + fileInputStream.close(); + } + } + finally { + tempFile.delete(); + } + } + + private static boolean delete(File file) { + boolean success = true; + if(file.isDirectory()) { + for (File child : file.listFiles()) { + success = success && delete(child); + } + } + + return file.delete() && success; + } + + public void testSmokeWithCompilerOutput() throws IOException { + File tempFile = File.createTempFile("compilerTest", "compilerTest"); + tempFile.delete(); + tempFile = new File(tempFile.getAbsolutePath()); + tempFile.mkdir(); + try { + KotlinCompiler.main(Arrays.asList("-src", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kt", "-output", tempFile.getAbsolutePath()).toArray(new String[0])); + assertEquals(1, tempFile.listFiles().length); + assertEquals(1, tempFile.listFiles()[0].listFiles().length); + } + finally { + delete(tempFile); + } + } + + private static List listEntries(JarInputStream is) throws IOException { List entries = new ArrayList(); while (true) { final JarEntry jarEntry = is.getNextJarEntry(); diff --git a/grammar/src/when.grm b/grammar/src/when.grm index d6769712963..4b0dd363a83 100644 --- a/grammar/src/when.grm +++ b/grammar/src/when.grm @@ -18,7 +18,6 @@ whenEntry whenCondition : expression - : ("." | "?.") postfixUnaryExpression typeArguments? valueArguments? : ("in" | "!in") expression : ("is" | "!is") isRHS ; diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java index b84b0f8af04..ac0d9be5ae1 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfiguration.java @@ -13,7 +13,6 @@ import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; -import com.intellij.openapi.util.text.StringUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -143,28 +142,35 @@ public class JetRunConfiguration extends ModuleBasedConfiguration.size : Int + get() = size() + + val Collection<*>.empty : Boolean + get() = isEmpty() +} \ No newline at end of file diff --git a/stdlib/ktSrc/StandardLibrary.kt b/stdlib/ktSrc/StandardLibrary.kt index 53d594e313a..999cecbad2c 100644 --- a/stdlib/ktSrc/StandardLibrary.kt +++ b/stdlib/ktSrc/StandardLibrary.kt @@ -1,15 +1,5 @@ namespace std -namespace util { - import java.util.* - - val Collection.size : Int - get() = size() - - val Collection.empty : Boolean - get() = isEmpty() -} - namespace io { import java.io.* import java.nio.charset.*