diff --git a/.idea/dictionaries/abreslav.xml b/.idea/dictionaries/abreslav.xml index 033e9a75f07ff128c1c57d5fb9098a4148051b57..265db740950bb1621562cd17ad099ba7c18ed459 100644 --- a/.idea/dictionaries/abreslav.xml +++ b/.idea/dictionaries/abreslav.xml @@ -2,6 +2,7 @@ accessor + dominator inferrer nondeterministic nullable diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 42c35e15901b6e1a9e8a74839cb8a3d0a03fcd72..d73a33835a24deba14a9dd84208648c7a1799564 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -265,9 +265,6 @@ public class JetControlFlowProcessor { builder.readUnit(expression); } builder.bindLabel(resultLabel); -// if (!inCondition) { -// builder.readNode(expression); -// } } @Override diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 6531bdf05b35c3419514c0e4a804486675e531d3..c3d790fe2516ba5c7405fd9e0af6ea16e117a0b2 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -10,18 +10,50 @@ import java.util.Collection; * @author abreslav */ public interface JetFlowInformationProvider { - JetFlowInformationProvider ERROR = new JetFlowInformationProvider() { + JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() { @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, Collection returnedExpressions, Collection elementsReturningUnit) { + public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { throw new UnsupportedOperationException(); } @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection unreachableElements) { + public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { + throw new UnsupportedOperationException(); + } + + @Override + public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { throw new UnsupportedOperationException(); } }; - void collectReturnedInformation(@NotNull JetElement subroutine, Collection returnedExpressions, Collection elementsReturningUnit); - void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection unreachableElements); + JetFlowInformationProvider NONE = new JetFlowInformationProvider() { + @Override + public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { + + } + + @Override + public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { + + } + + @Override + public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { + + } + }; + + void collectReturnedInformation( + @NotNull JetElement subroutine, + @NotNull Collection returnedExpressions, + @NotNull Collection elementsReturningUnit); + + void collectUnreachableExpressions( + @NotNull JetElement subroutine, + @NotNull Collection unreachableElements); + + void collectDominatedExpressions( + @NotNull JetExpression dominator, + @NotNull Collection dominated); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java index 521a28723ba0338bd997720bea560c77d84ec0e6..8a52116350be66b4f4c45afdf0eb1d74c44cdad8 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/AbstractJumpInstruction.java @@ -9,7 +9,7 @@ import java.util.Collections; /** * @author abreslav */ -public abstract class AbstractJumpInstruction extends Instruction { +public abstract class AbstractJumpInstruction extends InstructionImpl { private final Label targetLabel; private Instruction resolvedTarget; diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java index d2ae263ddd298a1a1b64253af0a974fada4d2f58..156f35debc2c256f2203a267c19aea39c865d278 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Instruction.java @@ -1,31 +1,22 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Collection; -import java.util.LinkedHashSet; /** -* @author abreslav -*/ -public abstract class Instruction { - private Collection previousInstructions = new LinkedHashSet(); + * @author abreslav + */ +public interface Instruction { + @NotNull + Pseudocode getOwner(); - public Collection getPreviousInstructions() { - return previousInstructions; - } + void setOwner(@NotNull Pseudocode owner); - @NotNull - public abstract Collection getNextInstructions(); + Collection getPreviousInstructions(); - @Nullable - protected Instruction outgoingEdgeTo(@Nullable Instruction target) { - if (target != null) { - target.getPreviousInstructions().add(this); - } - return target; - } + @NotNull + Collection getNextInstructions(); - public abstract void accept(InstructionVisitor visitor); + void accept(InstructionVisitor visitor); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b9c322f0f4c1fd3184dbe6044419306808132def --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionImpl.java @@ -0,0 +1,43 @@ +package org.jetbrains.jet.lang.cfg.pseudocode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.LinkedHashSet; + +/** +* @author abreslav +*/ +public abstract class InstructionImpl implements Instruction { + private Pseudocode owner; + private final Collection previousInstructions = new LinkedHashSet(); + + protected InstructionImpl() { + } + + @Override + @NotNull + public Pseudocode getOwner() { + return owner; + } + + @Override + public void setOwner(@NotNull Pseudocode owner) { + this.owner = owner; + } + + @Override + public Collection getPreviousInstructions() { + return previousInstructions; + } + + @Nullable + protected Instruction outgoingEdgeTo(@Nullable Instruction target) { + if (target != null) { + target.getPreviousInstructions().add(this); + } + return target; + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 181e16fbb33bac3523c7b4ca2e58092f2cf3abf8..0441a7e4aa631b6a9271fd620680a88dd4c1b7a3 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -83,8 +83,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd return pseudocode; } - private void add(Instruction instruction) { + private void add(@NotNull Instruction instruction) { pseudocode.addInstruction(instruction); + instruction.setOwner(pseudocode); + if (instruction instanceof JetElementInstruction) { + JetElementInstruction elementInstruction = (JetElementInstruction) instruction; + trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction); + } } @NotNull diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java index cc1b8ad4424f7b9418928fcfb995d8cde2daf446..86c9a72eaf5f0e3c904a283fee1885db18106284 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java @@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement; /** * @author abreslav */ -public interface JetElementInstruction { +public interface JetElementInstruction extends Instruction { @NotNull JetElement getElement(); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstructionImpl.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstructionImpl.java index 53d180ca1112726a933b75fdd041ed387280c57a..34f733bf9b41b210a22a0cb78ec641058c9084ec 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstructionImpl.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstructionImpl.java @@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement; /** * @author abreslav */ -public abstract class JetElementInstructionImpl extends Instruction implements JetElementInstruction { +public abstract class JetElementInstructionImpl extends InstructionImpl implements JetElementInstruction { protected final JetElement element; public JetElementInstructionImpl(@NotNull JetElement element) { diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java index 7cc5a86e6a995ed08d9dc39d411212fa98fdad23..39714a59fa03951b67323da57fbd4a42729e412e 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetPseudocodeTrace.java @@ -13,12 +13,18 @@ public interface JetPseudocodeTrace { public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { } + @Override + public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { + + } + @Override public void close() { } }; void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode); + void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction); void close(); } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/SubroutineExitInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/SubroutineExitInstruction.java index e46750724e42894f8f4705c908a8c39775906e42..56570b3b5c54bf9a6c697b1d5c4267981e8d3b68 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/SubroutineExitInstruction.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/SubroutineExitInstruction.java @@ -9,7 +9,7 @@ import java.util.Collections; /** * @author abreslav */ -public class SubroutineExitInstruction extends Instruction { +public class SubroutineExitInstruction extends InstructionImpl { private final JetElement subroutine; public SubroutineExitInstruction(@NotNull JetElement subroutine) { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/idea/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 96d0e7425f0c7048e5a5bdf3219de029637a26bd..02c8c3e1d20be8db3927e829ae7af2b92b47c3b6 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -3,6 +3,10 @@ package org.jetbrains.jet.lang.psi; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + /** * @author abreslav */ @@ -20,4 +24,27 @@ public class JetPsiUtil { public static String safeName(String name) { return name == null ? "" : name; } + + @NotNull + public static Set findRootExpressions(@NotNull Collection unreachableElements) { + Set rootElements = new HashSet(); + final Set shadowedElements = new HashSet(); + JetVisitor shadowAllChildren = new JetVisitor() { + @Override + public void visitJetElement(JetElement elem) { + if (shadowedElements.add(elem)) { + elem.acceptChildren(this); + } + } + }; + + for (JetElement element : unreachableElements) { + if (shadowedElements.contains(element)) continue; + element.acceptChildren(shadowAllChildren); + + rootElements.removeAll(shadowedElements); + rootElements.add(element); + } + return rootElements; + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 2293ab8221ee1b905697dfadbee6e42464da83f1..a7c9c9ffe39b809132b8f36ed5e3a016271d50f0 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -27,4 +27,5 @@ public interface BindingContext { PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor); boolean isBlock(JetFunctionLiteralExpression expression); + boolean isStatement(JetExpression expression); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 28ba5980e191c1f20b2995e571491c18f7016af4..694b4ec2086e129a93eda0a45f2eb0cedc17da46 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -21,6 +21,8 @@ public class BindingTraceContext extends BindingTrace implements BindingContext private final Map descriptorToDeclarations = new HashMap(); private final Map declarationsToDescriptors = new HashMap(); private final Set blocks = new HashSet(); + private final Set statements = new HashSet(); + private JetScope toplevelScope; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -61,6 +63,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext blocks.add(expression); } + @Override + public void recordStatement(@NotNull JetElement statement) { + statements.add(statement); + } + public void setToplevelScope(JetScope toplevelScope) { this.toplevelScope = toplevelScope; } @@ -135,4 +142,9 @@ public class BindingTraceContext extends BindingTrace implements BindingContext public boolean isBlock(JetFunctionLiteralExpression expression) { return !expression.hasParameterSpecification() && blocks.contains(expression); } + + @Override + public boolean isStatement(@NotNull JetExpression expression) { + return statements.contains(expression); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 89d0b2188980ce6f158ae18ed82792167dcccf6b..849b8aeafd817df0dbb7de4ca7623bf2380a5325 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -309,7 +309,7 @@ public class ClassDescriptorResolver { type = ErrorUtils.createErrorType("No type, no body"); } else { // TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}" - type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(scope, initializer, false); + type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(scope, initializer, false); } } else { type = typeResolver.resolveType(scope, propertyTypeRef); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 4873be4340318d1d39b43e6da3a55f59a9edc5c2..143bb9bd446a27acb3ae182ca65d013413c4c5af 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -96,7 +96,7 @@ public class TopDownAnalyzer { if (importDirective.isAllUnder()) { JetExpression importedReference = importDirective.getImportedReference(); if (importedReference != null) { - JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(namespaceScope, importedReference, false); + JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(namespaceScope, importedReference, false); if (type != null) { namespaceScope.importScope(type.getMemberScope()); } @@ -288,7 +288,7 @@ public class TopDownAnalyzer { flowInformationProvider.collectUnreachableExpressions(function, unreachableElements); // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well - Set rootElements = findRootExpressions(unreachableElements); + Set rootElements = JetPsiUtil.findRootExpressions(unreachableElements); // TODO : (return 1) || (return 2) -- only || and right of it is unreachable // TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable, @@ -318,31 +318,10 @@ public class TopDownAnalyzer { } } - private Set findRootExpressions(List unreachableElements) { - Set rootElements = new HashSet(); - final Set shadowedElements = new HashSet(); - JetVisitor shadowAllChildren = new JetVisitor() { - @Override - public void visitJetElement(JetElement elem) { - if (shadowedElements.add(elem)) { - elem.acceptChildren(this); - } - } - }; - - for (JetElement element : unreachableElements) { - if (shadowedElements.contains(element)) continue; - element.acceptChildren(shadowAllChildren); - - rootElements.removeAll(shadowedElements); - rootElements.add(element); - } - return rootElements; - } - private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) { final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); final Map pseudocodeMap = new HashMap(); + final Map representativeInstructions = new HashMap(); JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { @Override public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { @@ -350,6 +329,12 @@ public class TopDownAnalyzer { pseudocodeMap.put(element, pseudocode); } + @Override + public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { + Instruction oldValue = representativeInstructions.put(element, instruction); +// assert oldValue == null : element.getText(); + } + @Override public void close() { pseudocodeTrace.close(); @@ -363,7 +348,7 @@ public class TopDownAnalyzer { wrappedTrace.close(); return new JetFlowInformationProvider() { @Override - public void collectReturnedInformation(@NotNull JetElement subroutine, Collection returnedExpressions, Collection elementsReturningUnit) { + public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection returnedExpressions, @NotNull Collection elementsReturningUnit) { Pseudocode pseudocode = pseudocodeMap.get(subroutine); assert pseudocode != null; @@ -372,7 +357,7 @@ public class TopDownAnalyzer { } @Override - public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection unreachableElements) { + public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection unreachableElements) { Pseudocode pseudocode = pseudocodeMap.get(subroutine); assert pseudocode != null; @@ -385,7 +370,38 @@ public class TopDownAnalyzer { unreachableElements.add(((JetElementInstruction) instruction).getElement()); } } + } + + @Override + public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection dominated) { + Instruction dominatorInstruction = representativeInstructions.get(dominator); + if (dominatorInstruction == null) { +// assert +// dominator instanceof JetContinueExpression || +// dominator instanceof JetBreakExpression || +// dominator instanceof JetReturnExpression || +// dominator instanceof JetBlockExpression || +// dominator instanceof JetFunctionLiteralExpression +// : "No representative instruction for a Nothing-typed expression: " + dominator.getText(); + return; + } + SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction(); + + Set reachable = new HashSet(); + collectReachable(enterInstruction, reachable); + + Set reachableWithDominatorProhibited = new HashSet(); + reachableWithDominatorProhibited.add(dominatorInstruction); + collectReachable(enterInstruction, reachableWithDominatorProhibited); + for (Instruction instruction : reachable) { + if (instruction instanceof JetElementInstruction + && reachable.contains(instruction) + && !reachableWithDominatorProhibited.contains(instruction)) { + JetElementInstruction elementInstruction = (JetElementInstruction) instruction; + dominated.add(elementInstruction.getElement()); + } + } } }; } diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index 35ef7460a798de5a0fa7e2cb175fe9cfc55c6a79..27ca59bd570d3e887ba2684e63747da1e44ab4a7 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -38,6 +38,10 @@ public class BindingTrace { } + public void recordStatement(@NotNull JetElement statement) { + + } + public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) { } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 502d9c7d5c7d54c0407a2fb1fb07896f60ac07ea..2a7a07109e19d80fdb9fb4a2589146410f1b4b4d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -250,7 +250,8 @@ public class JetStandardClasses { } public static boolean isNothing(@NotNull JetType type) { - return type.getConstructor() == NOTHING_CLASS.getTypeConstructor(); + return !(type instanceof NamespaceType) && + type.getConstructor() == NOTHING_CLASS.getTypeConstructor(); } public static JetType getTupleType(List attributes, List arguments) { diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index dd763d70bc82783d18ae7fac5e53870e86ac7468..9994d269023dc7909d96a588f5a4d13ade3d85f6 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -356,7 +356,9 @@ public class JetTypeInferrer { JetType result = null; for (JetElement statement : block) { - result = blockLevelVisitor.getType((JetExpression) statement); + trace.recordStatement(statement); + JetExpression statementExpression = (JetExpression) statement; + result = blockLevelVisitor.getType(statementExpression); blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope? } return result; @@ -407,7 +409,11 @@ public class JetTypeInferrer { expression.accept(this); if (result != null) { trace.recordExpressionType(expression, result); + if (JetStandardClasses.isNothing(result)) { + markDominatedExpressionsAsUnreachable(expression); + } } + return result; } @@ -415,6 +421,18 @@ public class JetTypeInferrer { result = null; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + private void markDominatedExpressionsAsUnreachable(JetExpression expression) { + List dominated = new ArrayList(); + flowInformationProvider.collectDominatedExpressions(expression, dominated); + Set rootExpressions = JetPsiUtil.findRootExpressions(dominated); + for (JetElement rootExpression : rootExpressions) { + semanticServices.getErrorHandler().genericError(rootExpression.getNode(), + "This code is unreachable, because '" + expression.getText() + "' never terminates normally"); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override @@ -488,7 +506,7 @@ public class JetTypeInferrer { } JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType; JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("") : returnType; - result = JetStandardClasses.getFunctionType(null, effectiveReceiverType, parameterTypes, safeReturnType); + result = JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, safeReturnType); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java index 8e4c565f510e9360a6a6a1e84231013dc6d22497..e11ce4d10123c3db188fabe89aafd105f4e585db 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/JetQuickDocumentationProvider.java @@ -1,7 +1,8 @@ package org.jetbrains.jet.plugin; -import com.intellij.lang.documentation.QuickDocumentationProvider; +import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.psi.JetFile; @@ -11,10 +12,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.DeclarationDescriptor; import org.jetbrains.jet.resolve.DescriptorUtil; +import java.util.Collections; +import java.util.List; + /** * @author abreslav */ -public class JetQuickDocumentationProvider extends QuickDocumentationProvider { +public class JetQuickDocumentationProvider implements DocumentationProvider { @Override public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { @@ -51,5 +55,23 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider { return text; } + @Override + public List getUrlFor(PsiElement element, PsiElement originalElement) { + return Collections.emptyList(); + } + + @Override + public String generateDoc(PsiElement element, PsiElement originalElement) { + return ""; + } + @Override + public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) { + return null; + } + + @Override + public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) { + return null; + } } diff --git a/idea/testData/cfg/Finally.instructions b/idea/testData/cfg/Finally.instructions index e118850b4b6d1b9b34dec2d9c065a6de662b7d1f..f34ec57fe37b81da695995f4919b0e68c0038d33 100644 --- a/idea/testData/cfg/Finally.instructions +++ b/idea/testData/cfg/Finally.instructions @@ -435,3 +435,26 @@ l3: l1: ===================== +== tf == +fun tf() { + try { + return 1 + } + finally { + return 2 + } +} +--------------------- +l0: + + jmp?(l2) + r(1) + r(2) + ret(*) l1 + ret(*) l1 +l2: + r(2) + ret(*) l1 +l1: + +===================== diff --git a/idea/testData/checker/UnreachableCode.jet b/idea/testData/checker/UnreachableCode.jet index fe4b113f4d80ceb3f7ca1e53fe7788cfc52dc39e..6257c7d69af1c3c303d0fb1152ca3e0f0e3525a0 100644 --- a/idea/testData/checker/UnreachableCode.jet +++ b/idea/testData/checker/UnreachableCode.jet @@ -127,10 +127,10 @@ fun t8() { fun blockAndAndMismatch() : Boolean { (return true) || (return false) - 1 + true } fun tf() { - try {return} finally{return} + try {return} finally{return} 1 } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java index 56357f955fb3a6513264d6f2461de91fb7b5914b..26a9277cc8a64f19879b6018a8657a6b2d71ec2e 100644 --- a/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java +++ b/idea/tests/org/jetbrains/jet/cfg/JetControlFlowTest.java @@ -56,6 +56,10 @@ public class JetControlFlowTest extends JetTestCaseBase { } } + @Override + public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) { + } + }; AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() { diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 78a674ae48eb3a2ff625f3ad488aef0f008685ab..7eb350ed4afc777f0e28e6b8cee679a05928def7 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -459,14 +459,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(String expression, JetType expectedType) { Project project = getProject(); JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(classDefinitions.BASIC_SCOPE, jetExpression, false); + JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).getType(classDefinitions.BASIC_SCOPE, jetExpression, false); assertTrue(type + " != " + expectedType, JetTypeImpl.equalTypes(type, expectedType)); } private void assertErrorType(String expression) { Project project = getProject(); JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false); + JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false); assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type)); } @@ -489,7 +489,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private void assertType(JetScope scope, String expression, String expectedTypeStr) { Project project = getProject(); JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); - JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(scope, jetExpression, false); + JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).getType(scope, jetExpression, false); JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr); assertEquals(expectedType, type); }