KT-234 Force when() expressions to have an 'else' branch
KT-973 Unreachable code
This commit is contained in:
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
* @author abreslav
|
||||
*/
|
||||
public interface JetControlFlowBuilder {
|
||||
void read(@NotNull JetExpression expression);
|
||||
void read(@NotNull JetElement element);
|
||||
void readUnit(@NotNull JetExpression expression);
|
||||
|
||||
// General label management
|
||||
|
||||
@@ -13,9 +13,9 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
||||
protected @Nullable JetControlFlowBuilder builder;
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetExpression expression) {
|
||||
public void read(@NotNull JetElement element) {
|
||||
assert builder != null;
|
||||
builder.read(expression);
|
||||
builder.read(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -746,6 +746,7 @@ public class JetControlFlowProcessor {
|
||||
if (subjectExpression != null) {
|
||||
value(subjectExpression, inCondition);
|
||||
}
|
||||
boolean hasElseOrIrrefutableBranch = false;
|
||||
|
||||
Label doneLabel = builder.createUnboundLabel();
|
||||
|
||||
@@ -753,11 +754,18 @@ public class JetControlFlowProcessor {
|
||||
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
||||
JetWhenEntry whenEntry = iterator.next();
|
||||
|
||||
builder.read(whenEntry);
|
||||
|
||||
if (whenEntry.isElse()) {
|
||||
hasElseOrIrrefutableBranch = true;
|
||||
if (iterator.hasNext()) {
|
||||
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
||||
}
|
||||
}
|
||||
boolean isIrrefutable = JetPsiUtil.isIrrefutable(whenEntry);
|
||||
if (isIrrefutable) {
|
||||
hasElseOrIrrefutableBranch = true;
|
||||
}
|
||||
|
||||
Label bodyLabel = builder.createUnboundLabel();
|
||||
|
||||
@@ -770,17 +778,22 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
builder.nondeterministicJump(nextLabel);
|
||||
if (!isIrrefutable) {
|
||||
builder.nondeterministicJump(nextLabel);
|
||||
}
|
||||
|
||||
builder.bindLabel(bodyLabel);
|
||||
value(whenEntry.getExpression(), inCondition);
|
||||
builder.allowDead();
|
||||
builder.jump(doneLabel);
|
||||
builder.bindLabel(nextLabel);
|
||||
nextLabel = builder.createUnboundLabel();
|
||||
}
|
||||
// TODO : if there's else, no error can happen
|
||||
builder.jumpToError(null);
|
||||
builder.bindLabel(doneLabel);
|
||||
if (!hasElseOrIrrefutableBranch) {
|
||||
trace.report(NO_ELSE_IN_WHEN.on(expression));
|
||||
}
|
||||
builder.stopAllowDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -74,7 +74,7 @@ public class JetFlowInformationProvider {
|
||||
wrappedTrace.close();
|
||||
}
|
||||
|
||||
private void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
|
||||
private void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetElement> returnedExpressions) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
@@ -85,14 +85,14 @@ public class JetFlowInformationProvider {
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
if (instructions.contains(instruction)) { //exclude non-local return expressions
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
returnedExpressions.add(instruction.getElement());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
if (instructions.contains(instruction)) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
returnedExpressions.add(instruction.getElement());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class JetFlowInformationProvider {
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
if (instruction instanceof JetElementInstruction) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
returnedExpressions.add((JetExpression) elementInstruction.getElement());
|
||||
returnedExpressions.add(elementInstruction.getElement());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(instruction + " precedes the exit point");
|
||||
@@ -138,7 +138,7 @@ public class JetFlowInformationProvider {
|
||||
JetExpression bodyExpression = function.getBodyExpression();
|
||||
if (bodyExpression == null) return;
|
||||
|
||||
List<JetExpression> returnedExpressions = Lists.newArrayList();
|
||||
List<JetElement> returnedExpressions = Lists.newArrayList();
|
||||
collectReturnExpressions(function.asElement(), returnedExpressions);
|
||||
|
||||
boolean nothingReturned = returnedExpressions.isEmpty();
|
||||
@@ -155,7 +155,7 @@ public class JetFlowInformationProvider {
|
||||
trace.report(UNREACHABLE_CODE.on(element));
|
||||
}
|
||||
|
||||
for (JetExpression returnedExpression : returnedExpressions) {
|
||||
for (JetElement returnedExpression : returnedExpressions) {
|
||||
returnedExpression.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitReturnExpression(JetReturnExpression expression) {
|
||||
|
||||
+2
-2
@@ -227,8 +227,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetExpression expression) {
|
||||
add(new ReadValueInstruction(expression));
|
||||
public void read(@NotNull JetElement element) {
|
||||
add(new ReadValueInstruction(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,7 +33,7 @@ public class Pseudocode {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getTargetInstructionIndex() {
|
||||
public Integer getTargetInstructionIndex() {
|
||||
return targetInstructionIndex;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class ReadValueInstruction extends InstructionWithNext {
|
||||
|
||||
public ReadValueInstruction(@NotNull JetExpression expression) {
|
||||
super(expression);
|
||||
public ReadValueInstruction(@NotNull JetElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -263,7 +263,22 @@ public interface Errors {
|
||||
ParameterizedDiagnosticFactory1<CallableDescriptor> TOO_MANY_ARGUMENTS = ParameterizedDiagnosticFactory1.create(ERROR, "Too many arguments for {0}");
|
||||
ParameterizedDiagnosticFactory1<String> ERROR_COMPILE_TIME_VALUE = ParameterizedDiagnosticFactory1.create(ERROR, "{0}");
|
||||
|
||||
SimpleDiagnosticFactory ELSE_MISPLACED_IN_WHEN = SimpleDiagnosticFactory.create(ERROR, "'else' entry must be the last one in a when-expression");
|
||||
SimpleDiagnosticFactoryWithPsiElement<JetWhenEntry> ELSE_MISPLACED_IN_WHEN = new SimpleDiagnosticFactoryWithPsiElement<JetWhenEntry>(ERROR, "'else' entry must be the last one in a when-expression") {
|
||||
@NotNull
|
||||
@Override
|
||||
public TextRange getTextRange(@NotNull JetWhenEntry entry) {
|
||||
PsiElement elseKeywordElement = entry.getElseKeywordElement();
|
||||
assert elseKeywordElement != null;
|
||||
return elseKeywordElement.getTextRange();
|
||||
}
|
||||
};
|
||||
SimpleDiagnosticFactoryWithPsiElement<JetWhenExpression> NO_ELSE_IN_WHEN = new SimpleDiagnosticFactoryWithPsiElement<JetWhenExpression>(ERROR, "'when' expression must contain 'else' branch") {
|
||||
@NotNull
|
||||
@Override
|
||||
public TextRange getTextRange(@NotNull JetWhenExpression element) {
|
||||
return element.getWhenKeywordElement().getTextRange();
|
||||
}
|
||||
};
|
||||
SimpleDiagnosticFactory CYCLIC_INHERITANCE_HIERARCHY = SimpleDiagnosticFactory.create(ERROR, "There's a cycle in the inheritance hierarchy for this type");
|
||||
|
||||
SimpleDiagnosticFactory MANY_CLASSES_IN_SUPERTYPE_LIST = SimpleDiagnosticFactory.create(ERROR, "Only one class may appear in a supertype list");
|
||||
|
||||
+13
-3
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.diagnostics;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -15,19 +16,28 @@ public abstract class SimpleDiagnosticFactoryWithPsiElement<T extends PsiElement
|
||||
super(severity);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private Diagnostic on(@NotNull T elementToBlame, @NotNull TextRange textRange) {
|
||||
return new DiagnosticWithPsiElementImpl<T>(this, severity, message, elementToBlame, textRange);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull T elementToBlame, @NotNull ASTNode nodeToMark) {
|
||||
return new DiagnosticWithPsiElementImpl<T>(this, severity, message, elementToBlame, nodeToMark.getTextRange());
|
||||
return on(elementToBlame, nodeToMark.getTextRange());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull T elementToBlame, @NotNull PsiElement elementToMark) {
|
||||
return new DiagnosticWithPsiElementImpl<T>(this, severity, message, elementToBlame, elementToMark.getTextRange());
|
||||
return on(elementToBlame, elementToMark.getTextRange());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Diagnostic on(@NotNull T element) {
|
||||
return on(element, element.getNode());
|
||||
return on(element, getTextRange(element));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TextRange getTextRange(@NotNull T element) {
|
||||
return element.getTextRange();
|
||||
}
|
||||
}
|
||||
@@ -148,4 +148,23 @@ public class JetPsiUtil {
|
||||
private static String makeFQName(String prefix, JetClassOrObject jetClass) {
|
||||
return ((prefix == null || prefix.length() == 0) ? "" : prefix + ".") + jetClass.getName();
|
||||
}
|
||||
|
||||
public static boolean isIrrefutable(JetWhenEntry entry) {
|
||||
if (entry.isElse()) return true;
|
||||
for (JetWhenCondition condition : entry.getConditions()) {
|
||||
if (condition instanceof JetWhenConditionIsPattern) {
|
||||
JetPattern pattern = ((JetWhenConditionIsPattern) condition).getPattern();
|
||||
if (pattern instanceof JetWildcardPattern) {
|
||||
return true;
|
||||
}
|
||||
if (pattern instanceof JetBindingPattern) {
|
||||
JetBindingPattern bindingPattern = (JetBindingPattern) pattern;
|
||||
if (bindingPattern.getVariableDeclaration().getPropertyTypeRef() == null && bindingPattern.getCondition() == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
@@ -14,7 +15,12 @@ public class JetWhenEntry extends JetElement {
|
||||
}
|
||||
|
||||
public boolean isElse() {
|
||||
return findChildByType(JetTokens.ELSE_KEYWORD) != null;
|
||||
return getElseKeywordElement() != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getElseKeywordElement() {
|
||||
return findChildByType(JetTokens.ELSE_KEYWORD);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -34,4 +36,9 @@ public class JetWhenExpression extends JetExpression {
|
||||
public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
|
||||
return visitor.visitWhenExpression(this, data);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement getWhenKeywordElement() {
|
||||
return findChildByType(JetTokens.WHEN_KEYWORD);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user