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 00ca48cc64a..bd489bdb0d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -39,6 +39,10 @@ public interface JetControlFlowBuilder { @Nullable JetElement getReturnSubroutine(); + // Lexical scopes + void enterLexicalScope(@NotNull JetElement element); + void exitLexicalScope(@NotNull JetElement element); + // Entry/exit points @NotNull Label getEntryPoint(@NotNull JetElement labelElement); 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 c5958f12d18..842ef3c6499 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -239,4 +239,14 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil public void mark(@NotNull JetElement element) { getDelegateBuilder().mark(element); } + + @Override + public void enterLexicalScope(@NotNull JetElement element) { + getDelegateBuilder().enterLexicalScope(element); + } + + @Override + public void exitLexicalScope(@NotNull JetElement element) { + getDelegateBuilder().exitLexicalScope(element); + } } 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 481e14cee3f..eba98ed267c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -507,6 +507,7 @@ public class JetControlFlowProcessor { } boolean isFirst = true; for (JetCatchClause catchClause : catchClauses) { + builder.enterLexicalScope(catchClause); if (!isFirst) { builder.bindLabel(catchLabels.remove()); } @@ -523,6 +524,7 @@ public class JetControlFlowProcessor { generateInstructions(catchBody, NOT_IN_CONDITION); } builder.jump(afterCatches); + builder.exitLexicalScope(catchClause); } builder.bindLabel(afterCatches); @@ -578,6 +580,7 @@ public class JetControlFlowProcessor { @Override public void visitDoWhileExpressionVoid(@NotNull JetDoWhileExpression expression, CFPContext context) { + builder.enterLexicalScope(expression); mark(expression); LoopInfo loopInfo = builder.enterLoop(expression, null, null); @@ -594,10 +597,12 @@ public class JetControlFlowProcessor { builder.jumpOnTrue(loopInfo.getEntryPoint()); builder.exitLoop(expression); builder.loadUnit(expression); + builder.exitLexicalScope(expression); } @Override public void visitForExpressionVoid(@NotNull JetForExpression expression, CFPContext context) { + builder.enterLexicalScope(expression); mark(expression); JetExpression loopRange = expression.getLoopRange(); if (loopRange != null) { @@ -630,6 +635,7 @@ public class JetControlFlowProcessor { builder.nondeterministicJump(loopInfo.getEntryPoint()); builder.exitLoop(expression); builder.loadUnit(expression); + builder.exitLexicalScope(expression); } @Override @@ -731,6 +737,10 @@ public class JetControlFlowProcessor { @Override public void visitBlockExpressionVoid(@NotNull JetBlockExpression expression, CFPContext context) { + boolean declareLexicalScope = !isBlockInDoWhile(expression); + if (declareLexicalScope) { + builder.enterLexicalScope(expression); + } mark(expression); List statements = expression.getStatements(); for (JetElement statement : statements) { @@ -739,6 +749,15 @@ public class JetControlFlowProcessor { if (statements.isEmpty()) { builder.loadUnit(expression); } + if (declareLexicalScope) { + builder.exitLexicalScope(expression); + } + } + + private boolean isBlockInDoWhile(@NotNull JetBlockExpression expression) { + PsiElement parent = expression.getParent(); + if (parent == null) return false; + return parent.getParent() instanceof JetDoWhileExpression; } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java index a37d8f3ad2c..b9ae00bd85c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java @@ -26,7 +26,8 @@ public abstract class AbstractJumpInstruction extends InstructionImpl { private final Label targetLabel; private Instruction resolvedTarget; - public AbstractJumpInstruction(Label targetLabel) { + public AbstractJumpInstruction(Label targetLabel, LexicalScope lexicalScope) { + super(lexicalScope); this.targetLabel = targetLabel; } @@ -48,15 +49,15 @@ public abstract class AbstractJumpInstruction extends InstructionImpl { this.resolvedTarget = outgoingEdgeTo(resolvedTarget); } - protected abstract AbstractJumpInstruction createCopy(@NotNull Label newLabel); + protected abstract AbstractJumpInstruction createCopy(@NotNull Label newLabel, @NotNull LexicalScope lexicalScope); final public Instruction copy(@NotNull Label newLabel) { - return updateCopyInfo(createCopy(newLabel)); + return updateCopyInfo(createCopy(newLabel, lexicalScope)); } @NotNull @Override protected Instruction createCopy() { - return createCopy(targetLabel); + return createCopy(targetLabel, lexicalScope); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/ConditionalJumpInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/ConditionalJumpInstruction.java index c2fdf67b1c2..903f6be843a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/ConditionalJumpInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/ConditionalJumpInstruction.java @@ -27,8 +27,8 @@ public class ConditionalJumpInstruction extends AbstractJumpInstruction { private Instruction nextOnTrue; private Instruction nextOnFalse; - public ConditionalJumpInstruction(boolean onTrue, Label targetLabel) { - super(targetLabel); + public ConditionalJumpInstruction(boolean onTrue, LexicalScope lexicalScope, Label targetLabel) { + super(targetLabel, lexicalScope); this.onTrue = onTrue; } @@ -75,7 +75,7 @@ public class ConditionalJumpInstruction extends AbstractJumpInstruction { } @Override - protected AbstractJumpInstruction createCopy(@NotNull Label newLabel) { - return new ConditionalJumpInstruction(onTrue, newLabel); + protected AbstractJumpInstruction createCopy(@NotNull Label newLabel, @NotNull LexicalScope lexicalScope) { + return new ConditionalJumpInstruction(onTrue, lexicalScope, newLabel); } } 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 bc20d5261fa..3eceb5a449c 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 @@ -37,4 +37,7 @@ public interface Instruction { @NotNull Collection getCopies(); + + @NotNull + LexicalScope getLexicalScope(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java index f14cfdddbae..4928ceada74 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java @@ -27,10 +27,13 @@ public abstract class InstructionImpl implements Instruction { private Pseudocode owner; private final Collection previousInstructions = new LinkedHashSet(); private final Collection copies = Sets.newHashSet(); + @NotNull + protected final LexicalScope lexicalScope; private Instruction original; protected boolean isDead = false; - protected InstructionImpl() { + protected InstructionImpl(@NotNull LexicalScope lexicalScope) { + this.lexicalScope = lexicalScope; } @Override @@ -96,6 +99,12 @@ public abstract class InstructionImpl implements Instruction { this.original = original; } + @NotNull + @Override + public LexicalScope getLexicalScope() { + return lexicalScope; + } + protected Instruction updateCopyInfo(@NotNull Instruction instruction) { addCopy(instruction); ((InstructionImpl)instruction).setOriginal(this); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java index ff0bcd6355a..b7f7eed227d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java @@ -25,8 +25,8 @@ import java.util.Collections; public abstract class InstructionWithNext extends JetElementInstructionImpl { private Instruction next; - protected InstructionWithNext(@NotNull JetElement element) { - super(element); + protected InstructionWithNext(@NotNull JetElement element, @NotNull LexicalScope lexicalScope) { + super(element, lexicalScope); } public Instruction getNext() { 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 616bfad3b82..79d3107aeb4 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 @@ -36,6 +36,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd private JetControlFlowBuilder builder = null; private final Stack loopInfo = new Stack(); + private final Stack lexicalScopes = new Stack(); private final Map elementToBlockInfo = new HashMap(); private int labelCount = 0; private int allowDeadLabelCount = 0; @@ -76,6 +77,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd pushBuilder(subroutine, subroutine); } assert builder != null; + builder.enterLexicalScope(subroutine); builder.enterSubroutine(subroutine); } @@ -83,6 +85,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @Override public Pseudocode exitSubroutine(@NotNull JetElement subroutine) { super.exitSubroutine(subroutine); + builder.exitLexicalScope(subroutine); JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine); if (!builders.empty()) { JetControlFlowInstructionsGeneratorWorker builder = builders.peek(); @@ -163,7 +166,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd elementToBlockInfo.put(subroutine, blockInfo); allBlocks.push(blockInfo); bindLabel(entryPoint); - add(new SubroutineEnterInstruction(subroutine)); + add(new SubroutineEnterInstruction(subroutine, getCurrentScope())); } @NotNull @@ -191,7 +194,28 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd return blockInfo.getExitPoint(); } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + @NotNull + private LexicalScope getCurrentScope() { + return lexicalScopes.peek(); + } + + @Override + public void enterLexicalScope(@NotNull JetElement element) { + LexicalScope current = lexicalScopes.isEmpty() ? null : getCurrentScope(); + LexicalScope scope = new LexicalScope(current, element); + lexicalScopes.push(scope); + } + + @Override + public void exitLexicalScope(@NotNull JetElement element) { + LexicalScope currentScope = getCurrentScope(); + assert currentScope.getElement() == element : "Exit from not the current lexical scope.\n" + + "Current scope is for: " + currentScope.getElement() + ".\n" + + "Exit from the scope for: " + element.getText(); + lexicalScopes.pop(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void handleJumpInsideTryFinally(Label jumpTarget) { List finallyBlocks = new ArrayList(); @@ -219,11 +243,11 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @Override public Pseudocode exitSubroutine(@NotNull JetElement subroutine) { bindLabel(getExitPoint(subroutine)); - pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, false)); + pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, getCurrentScope(), false)); bindLabel(error); - pseudocode.addErrorInstruction(new SubroutineExitInstruction(subroutine, true)); + pseudocode.addErrorInstruction(new SubroutineExitInstruction(subroutine, getCurrentScope(), true)); bindLabel(sink); - pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, "")); + pseudocode.addSinkInstruction(new SubroutineSinkInstruction(subroutine, getCurrentScope(), "")); elementToBlockInfo.remove(subroutine); allBlocks.pop(); return pseudocode; @@ -231,64 +255,64 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @Override public void mark(@NotNull JetElement element) { - add(new MarkInstruction(element)); + add(new MarkInstruction(element, getCurrentScope())); } @Override public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) { Label exitPoint = getExitPoint(subroutine); handleJumpInsideTryFinally(exitPoint); - add(new ReturnValueInstruction(returnExpression, exitPoint)); + add(new ReturnValueInstruction(returnExpression, getCurrentScope(), exitPoint)); } @Override public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) { Label exitPoint = getExitPoint(subroutine); handleJumpInsideTryFinally(exitPoint); - add(new ReturnNoValueInstruction(returnExpression, exitPoint)); + add(new ReturnNoValueInstruction(returnExpression, getCurrentScope(), exitPoint)); } @Override public void write(@NotNull JetElement assignment, @NotNull JetElement lValue) { - add(new WriteValueInstruction(assignment, lValue)); + add(new WriteValueInstruction(assignment, lValue, getCurrentScope())); } @Override public void declareParameter(@NotNull JetParameter parameter) { - add(new VariableDeclarationInstruction(parameter)); + add(new VariableDeclarationInstruction(parameter, getCurrentScope())); } @Override public void declareVariable(@NotNull JetVariableDeclaration property) { - add(new VariableDeclarationInstruction(property)); + add(new VariableDeclarationInstruction(property, getCurrentScope())); } @Override public void declareFunction(@NotNull JetElement subroutine, @NotNull Pseudocode pseudocode) { - add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode)); + add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode, getCurrentScope())); } @Override public void loadUnit(@NotNull JetExpression expression) { - add(new LoadUnitValueInstruction(expression)); + add(new LoadUnitValueInstruction(expression, getCurrentScope())); } @Override public void jump(@NotNull Label label) { handleJumpInsideTryFinally(label); - add(new UnconditionalJumpInstruction(label)); + add(new UnconditionalJumpInstruction(label, getCurrentScope())); } @Override public void jumpOnFalse(@NotNull Label label) { handleJumpInsideTryFinally(label); - add(new ConditionalJumpInstruction(false, label)); + add(new ConditionalJumpInstruction(false, getCurrentScope(), label)); } @Override public void jumpOnTrue(@NotNull Label label) { handleJumpInsideTryFinally(label); - add(new ConditionalJumpInstruction(true, label)); + add(new ConditionalJumpInstruction(true, getCurrentScope(), label)); } @Override @@ -299,20 +323,20 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @Override public void nondeterministicJump(@NotNull Label label) { handleJumpInsideTryFinally(label); - add(new NondeterministicJumpInstruction(label)); + add(new NondeterministicJumpInstruction(label, getCurrentScope())); } @Override public void nondeterministicJump(@NotNull List