diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 545a248242b..17193241a1f 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -7,9 +7,8 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.Processor; -import jet.ExtensionFunction0; -import jet.modules.IModuleBuilder; -import jet.modules.IModuleSetBuilder; +import jet.modules.AllModules; +import jet.modules.Module; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GeneratedClassLoader; @@ -19,7 +18,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.plugin.JetMainDetector; import java.io.*; -import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.List; @@ -174,13 +173,14 @@ public class CompileEnvironment { e.printStackTrace(); } - final IModuleSetBuilder moduleSetBuilder = loadModuleScript(moduleFile); - if (moduleSetBuilder == null) { - return; + final List modules = loadModuleScript(moduleFile); + + if (modules == null) { + throw new CompileEnvironmentException("Module script " + moduleFile + " compilation failed"); } final String directory = new File(moduleFile).getParent(); - for (IModuleBuilder moduleBuilder : moduleSetBuilder.getModules()) { + for (Module moduleBuilder : modules) { ClassFileFactory moduleFactory = compileModule(moduleBuilder, directory); final String path = jarPath != null ? jarPath : new File(directory, moduleBuilder.getModuleName() + ".jar").getPath(); try { @@ -191,7 +191,7 @@ public class CompileEnvironment { } } - public IModuleSetBuilder loadModuleScript(String moduleFile) { + public List loadModuleScript(String moduleFile) { CompileSession scriptCompileSession = new CompileSession(myEnvironment); scriptCompileSession.addSources(moduleFile); scriptCompileSession.addStdLibSources(true); @@ -204,34 +204,25 @@ public class CompileEnvironment { return runDefineModules(moduleFile, factory); } - private static IModuleSetBuilder runDefineModules(String moduleFile, ClassFileFactory factory) { + private static List 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(JvmAbi.PACKAGE_CLASS); - final Field[] fields = namespaceClass.getDeclaredFields(); - boolean modulesDefined = false; - for (Field field : fields) { - if (field.getName().equals("modules")) { - field.setAccessible(true); - ExtensionFunction0 defineMudules = (ExtensionFunction0) field.get(null); - defineMudules.invoke(moduleSetBuilder); - modulesDefined = true; - break; - } + final Method method = namespaceClass.getDeclaredMethod("project"); + if (method == null) { + throw new CompileEnvironmentException("Module script " + moduleFile + " must define project() function"); } - if (!modulesDefined) { - throw new CompileEnvironmentException("Module script " + moduleFile + " must define a modules() property"); - } - return moduleSetBuilder; + + method.setAccessible(true); + method.invoke(null); + + return AllModules.modules; } catch (Exception e) { throw new CompileEnvironmentException(e); } } - public ClassFileFactory compileModule(IModuleBuilder moduleBuilder, String directory) { + public ClassFileFactory compileModule(Module moduleBuilder, String directory) { CompileSession moduleCompileSession = new CompileSession(myEnvironment); if (!"stdlib".equals(moduleBuilder.getModuleName())) { moduleCompileSession.addStdLibSources(false); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index b4581a9200a..31bfcec6ce7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -19,6 +19,7 @@ public interface JetControlFlowBuilder { void bindLabel(@NotNull Label label); void allowDead(); + void stopAllowDead(); // Jumps void jump(@NotNull Label label); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index d42a0cbd726..0c6ea512103 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -43,6 +43,12 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { builder.allowDead(); } + @Override + public void stopAllowDead() { + assert builder != null; + builder.stopAllowDead(); + } + @Override public void jump(@NotNull Label label) { assert builder != null; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java index 7befd95b142..9b35e30ec89 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphTraverser.java @@ -8,10 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.pseudocode.*; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @author svtk @@ -140,7 +137,6 @@ public class JetControlFlowGraphTraverser { Collections.reverse(instructions); } for (Instruction instruction : instructions) { - if (instruction.isDead()) continue; if (lookInside && instruction instanceof LocalDeclarationInstruction) { traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index c3dab813a27..d9897b438d8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -153,6 +153,8 @@ public class JetControlFlowProcessor { @Override public void visitParenthesizedExpression(JetParenthesizedExpression expression) { + builder.read(expression); + JetExpression innerExpression = expression.getExpression(); if (innerExpression != null) { value(innerExpression, inCondition); @@ -340,6 +342,7 @@ public class JetControlFlowProcessor { @Override public void visitTryExpression(JetTryExpression expression) { + builder.read(expression); final JetFinallySection finallyBlock = expression.getFinallyBlock(); if (finallyBlock != null) { builder.enterTryFinally(new GenerationTrigger() { @@ -408,10 +411,12 @@ public class JetControlFlowProcessor { builder.exitTryFinally(); value(finallyBlock.getFinalExpression(), inCondition); } + builder.stopAllowDead(); } @Override public void visitWhileExpression(JetWhileExpression expression) { + builder.read(expression); LoopInfo loopInfo = builder.enterLoop(expression, null, null); builder.bindLabel(loopInfo.getConditionEntryPoint()); @@ -433,6 +438,7 @@ public class JetControlFlowProcessor { @Override public void visitDoWhileExpression(JetDoWhileExpression expression) { + builder.read(expression); LoopInfo loopInfo = builder.enterLoop(expression, null, null); builder.bindLabel(loopInfo.getBodyEntryPoint()); @@ -452,6 +458,7 @@ public class JetControlFlowProcessor { @Override public void visitForExpression(JetForExpression expression) { + builder.read(expression); JetExpression loopRange = expression.getLoopRange(); if (loopRange != null) { value(loopRange, false); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 37c96d9dce7..c0284d377b5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -252,7 +252,10 @@ public class JetFlowInformationProvider { analyzeLocalDeclarations(processLocalDeclaration, pseudocode); } - private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, @NotNull JetElement element, @NotNull VariableInitializers variableInitializers, @NotNull Collection varWithUninitializedErrorGenerated) { + private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetElement element, + @NotNull VariableInitializers variableInitializers, + @NotNull Collection varWithUninitializedErrorGenerated) { if (!(element instanceof JetSimpleNameExpression)) return; boolean isInitialized = variableInitializers.isInitialized(); @@ -272,7 +275,10 @@ public class JetFlowInformationProvider { } } - private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection varWithValReassignErrorGenerated) { + private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, + @NotNull JetExpression expression, + @NotNull VariableInitializers enterInitializers, + @NotNull Collection varWithValReassignErrorGenerated) { boolean isInitializedNotHere = enterInitializers.isInitialized(); Set possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers(); if (possibleLocalInitializers.size() == 1) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java index 63f759c81d1..4a2cf3832e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java @@ -20,6 +20,4 @@ public interface Instruction { Collection getNextInstructions(); void accept(InstructionVisitor visitor); - - boolean isDead(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 0d6ac71d32c..71d5ffc290e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -190,7 +190,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd bindLabel(getExitPoint(subroutine)); pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, "")); bindLabel(error); - add(new SubroutineExitInstruction(subroutine, "")); + pseudocode.addErrorInstruction(new SubroutineExitInstruction(subroutine, "")); bindLabel(sink); pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, "")); elementToBlockInfo.remove(subroutine); @@ -266,6 +266,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd pseudocode.allowDead(allowedDeadLabel); } + @Override + public void stopAllowDead() { + Label allowedDeadLabel = createUnboundLabel(); + bindLabel(allowedDeadLabel); + pseudocode.stopAllowDead(allowedDeadLabel); + } + @Override public void nondeterministicJump(Label label) { handleJumpInsideTryFinally(label); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 520b52437a8..f9e1ea2ded1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -56,12 +56,16 @@ public class Pseudocode { private final List mutableInstructionList = new ArrayList(); private final List instructions = new ArrayList(); + private List deadInstructions; + private final List labels = new ArrayList(); private final List allowedDeadLabels = new ArrayList(); + private final List stopAllowDeadLabels = new ArrayList(); private final JetElement correspondingElement; private SubroutineExitInstruction exitInstruction; private SubroutineSinkInstruction sinkInstruction; + private SubroutineExitInstruction errorInstruction; private boolean postPrecessed = false; public Pseudocode(JetElement correspondingElement) { @@ -81,6 +85,10 @@ public class Pseudocode { public void allowDead(Label label) { allowedDeadLabels.add((PseudocodeLabel) label); } + + public void stopAllowDead(Label label) { + stopAllowDeadLabels.add((PseudocodeLabel) label); + } @NotNull public List getInstructions() { @@ -95,10 +103,17 @@ public class Pseudocode { @NotNull public List getDeadInstructions() { - List deadInstructions = Lists.newArrayList(); - for (Instruction instruction : instructions) { - if (instruction.isDead()) { - deadInstructions.add(instruction); + if (deadInstructions != null) { + return deadInstructions; + } + deadInstructions = Lists.newArrayList(); + Collection allowedDeadInstructions = collectAllowedDeadInstructions(); + + for (Instruction instruction : mutableInstructionList) { + if (((InstructionImpl)instruction).isDead()) { + if (!allowedDeadInstructions.contains(instruction)) { + deadInstructions.add(instruction); + } } } return deadInstructions; @@ -122,6 +137,12 @@ public class Pseudocode { this.sinkInstruction = sinkInstruction; } + public void addErrorInstruction(SubroutineExitInstruction errorInstruction) { + addInstruction(errorInstruction); + assert this.errorInstruction == null; + this.errorInstruction = errorInstruction; + } + public void addInstruction(Instruction instruction) { mutableInstructionList.add(instruction); instruction.setOwner(this); @@ -151,88 +172,107 @@ public class Pseudocode { if (postPrecessed) return; postPrecessed = true; for (int i = 0, instructionsSize = mutableInstructionList.size(); i < instructionsSize; i++) { - Instruction instruction = mutableInstructionList.get(i); - final int currentPosition = i; - instruction.accept(new InstructionVisitor() { - @Override - public void visitInstructionWithNext(InstructionWithNext instruction) { - instruction.setNext(getNextPosition(currentPosition)); - } - - @Override - public void visitJump(AbstractJumpInstruction instruction) { - instruction.setResolvedTarget(getJumpTarget(instruction.getTargetLabel())); - } - - @Override - public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { - instruction.setNext(getNextPosition(currentPosition)); - List