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
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetControlFlowBuilder {
|
public interface JetControlFlowBuilder {
|
||||||
void read(@NotNull JetExpression expression);
|
void read(@NotNull JetElement element);
|
||||||
void readUnit(@NotNull JetExpression expression);
|
void readUnit(@NotNull JetExpression expression);
|
||||||
|
|
||||||
// General label management
|
// General label management
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
protected @Nullable JetControlFlowBuilder builder;
|
protected @Nullable JetControlFlowBuilder builder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(@NotNull JetExpression expression) {
|
public void read(@NotNull JetElement element) {
|
||||||
assert builder != null;
|
assert builder != null;
|
||||||
builder.read(expression);
|
builder.read(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -746,6 +746,7 @@ public class JetControlFlowProcessor {
|
|||||||
if (subjectExpression != null) {
|
if (subjectExpression != null) {
|
||||||
value(subjectExpression, inCondition);
|
value(subjectExpression, inCondition);
|
||||||
}
|
}
|
||||||
|
boolean hasElseOrIrrefutableBranch = false;
|
||||||
|
|
||||||
Label doneLabel = builder.createUnboundLabel();
|
Label doneLabel = builder.createUnboundLabel();
|
||||||
|
|
||||||
@@ -753,11 +754,18 @@ public class JetControlFlowProcessor {
|
|||||||
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
||||||
JetWhenEntry whenEntry = iterator.next();
|
JetWhenEntry whenEntry = iterator.next();
|
||||||
|
|
||||||
|
builder.read(whenEntry);
|
||||||
|
|
||||||
if (whenEntry.isElse()) {
|
if (whenEntry.isElse()) {
|
||||||
|
hasElseOrIrrefutableBranch = true;
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
boolean isIrrefutable = JetPsiUtil.isIrrefutable(whenEntry);
|
||||||
|
if (isIrrefutable) {
|
||||||
|
hasElseOrIrrefutableBranch = true;
|
||||||
|
}
|
||||||
|
|
||||||
Label bodyLabel = builder.createUnboundLabel();
|
Label bodyLabel = builder.createUnboundLabel();
|
||||||
|
|
||||||
@@ -770,17 +778,22 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.nondeterministicJump(nextLabel);
|
if (!isIrrefutable) {
|
||||||
|
builder.nondeterministicJump(nextLabel);
|
||||||
|
}
|
||||||
|
|
||||||
builder.bindLabel(bodyLabel);
|
builder.bindLabel(bodyLabel);
|
||||||
value(whenEntry.getExpression(), inCondition);
|
value(whenEntry.getExpression(), inCondition);
|
||||||
|
builder.allowDead();
|
||||||
builder.jump(doneLabel);
|
builder.jump(doneLabel);
|
||||||
builder.bindLabel(nextLabel);
|
builder.bindLabel(nextLabel);
|
||||||
nextLabel = builder.createUnboundLabel();
|
nextLabel = builder.createUnboundLabel();
|
||||||
}
|
}
|
||||||
// TODO : if there's else, no error can happen
|
|
||||||
builder.jumpToError(null);
|
|
||||||
builder.bindLabel(doneLabel);
|
builder.bindLabel(doneLabel);
|
||||||
|
if (!hasElseOrIrrefutableBranch) {
|
||||||
|
trace.report(NO_ELSE_IN_WHEN.on(expression));
|
||||||
|
}
|
||||||
|
builder.stopAllowDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class JetFlowInformationProvider {
|
|||||||
wrappedTrace.close();
|
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);
|
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||||
assert pseudocode != null;
|
assert pseudocode != null;
|
||||||
|
|
||||||
@@ -85,14 +85,14 @@ public class JetFlowInformationProvider {
|
|||||||
@Override
|
@Override
|
||||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||||
if (instructions.contains(instruction)) { //exclude non-local return expressions
|
if (instructions.contains(instruction)) { //exclude non-local return expressions
|
||||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
returnedExpressions.add(instruction.getElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||||
if (instructions.contains(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) {
|
public void visitInstruction(Instruction instruction) {
|
||||||
if (instruction instanceof JetElementInstruction) {
|
if (instruction instanceof JetElementInstruction) {
|
||||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||||
returnedExpressions.add((JetExpression) elementInstruction.getElement());
|
returnedExpressions.add(elementInstruction.getElement());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalStateException(instruction + " precedes the exit point");
|
throw new IllegalStateException(instruction + " precedes the exit point");
|
||||||
@@ -138,7 +138,7 @@ public class JetFlowInformationProvider {
|
|||||||
JetExpression bodyExpression = function.getBodyExpression();
|
JetExpression bodyExpression = function.getBodyExpression();
|
||||||
if (bodyExpression == null) return;
|
if (bodyExpression == null) return;
|
||||||
|
|
||||||
List<JetExpression> returnedExpressions = Lists.newArrayList();
|
List<JetElement> returnedExpressions = Lists.newArrayList();
|
||||||
collectReturnExpressions(function.asElement(), returnedExpressions);
|
collectReturnExpressions(function.asElement(), returnedExpressions);
|
||||||
|
|
||||||
boolean nothingReturned = returnedExpressions.isEmpty();
|
boolean nothingReturned = returnedExpressions.isEmpty();
|
||||||
@@ -155,7 +155,7 @@ public class JetFlowInformationProvider {
|
|||||||
trace.report(UNREACHABLE_CODE.on(element));
|
trace.report(UNREACHABLE_CODE.on(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (JetExpression returnedExpression : returnedExpressions) {
|
for (JetElement returnedExpression : returnedExpressions) {
|
||||||
returnedExpression.accept(new JetVisitorVoid() {
|
returnedExpression.accept(new JetVisitorVoid() {
|
||||||
@Override
|
@Override
|
||||||
public void visitReturnExpression(JetReturnExpression expression) {
|
public void visitReturnExpression(JetReturnExpression expression) {
|
||||||
|
|||||||
+2
-2
@@ -227,8 +227,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(@NotNull JetExpression expression) {
|
public void read(@NotNull JetElement element) {
|
||||||
add(new ReadValueInstruction(expression));
|
add(new ReadValueInstruction(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class Pseudocode {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTargetInstructionIndex() {
|
public Integer getTargetInstructionIndex() {
|
||||||
return targetInstructionIndex;
|
return targetInstructionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,15 +1,15 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class ReadValueInstruction extends InstructionWithNext {
|
public class ReadValueInstruction extends InstructionWithNext {
|
||||||
|
|
||||||
public ReadValueInstruction(@NotNull JetExpression expression) {
|
public ReadValueInstruction(@NotNull JetElement element) {
|
||||||
super(expression);
|
super(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -263,7 +263,22 @@ public interface Errors {
|
|||||||
ParameterizedDiagnosticFactory1<CallableDescriptor> TOO_MANY_ARGUMENTS = ParameterizedDiagnosticFactory1.create(ERROR, "Too many arguments for {0}");
|
ParameterizedDiagnosticFactory1<CallableDescriptor> TOO_MANY_ARGUMENTS = ParameterizedDiagnosticFactory1.create(ERROR, "Too many arguments for {0}");
|
||||||
ParameterizedDiagnosticFactory1<String> ERROR_COMPILE_TIME_VALUE = ParameterizedDiagnosticFactory1.create(ERROR, "{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 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");
|
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;
|
package org.jetbrains.jet.lang.diagnostics;
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -15,19 +16,28 @@ public abstract class SimpleDiagnosticFactoryWithPsiElement<T extends PsiElement
|
|||||||
super(severity);
|
super(severity);
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Diagnostic on(@NotNull T elementToBlame, @NotNull TextRange textRange) {
|
||||||
|
return new DiagnosticWithPsiElementImpl<T>(this, severity, message, elementToBlame, textRange);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Diagnostic on(@NotNull T elementToBlame, @NotNull ASTNode nodeToMark) {
|
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
|
@NotNull
|
||||||
public Diagnostic on(@NotNull T elementToBlame, @NotNull PsiElement elementToMark) {
|
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
|
@NotNull
|
||||||
public Diagnostic on(@NotNull T element) {
|
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) {
|
private static String makeFQName(String prefix, JetClassOrObject jetClass) {
|
||||||
return ((prefix == null || prefix.length() == 0) ? "" : prefix + ".") + jetClass.getName();
|
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;
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
@@ -14,7 +15,12 @@ public class JetWhenEntry extends JetElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isElse() {
|
public boolean isElse() {
|
||||||
return findChildByType(JetTokens.ELSE_KEYWORD) != null;
|
return getElseKeywordElement() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PsiElement getElseKeywordElement() {
|
||||||
|
return findChildByType(JetTokens.ELSE_KEYWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package org.jetbrains.jet.lang.psi;
|
package org.jetbrains.jet.lang.psi;
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.List;
|
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) {
|
public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
|
||||||
return visitor.visitWhenExpression(this, data);
|
return visitor.visitWhenExpression(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public PsiElement getWhenKeywordElement() {
|
||||||
|
return findChildByType(JetTokens.WHEN_KEYWORD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
fun isZero(x: Int) = when(x) {
|
fun isZero(x: Int) = when(x) {
|
||||||
0 -> true
|
0 -> true
|
||||||
|
else -> throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ fun notAnExpression() {
|
|||||||
any(<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>) // not an expression
|
any(<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>) // not an expression
|
||||||
if (<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>) {} else {} // not an expression
|
if (<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>) {} else {} // not an expression
|
||||||
val <!UNUSED_VARIABLE!>x<!> = <!SUPER_IS_NOT_AN_EXPRESSION!>super<!> // not an expression
|
val <!UNUSED_VARIABLE!>x<!> = <!SUPER_IS_NOT_AN_EXPRESSION!>super<!> // not an expression
|
||||||
when (1) {
|
<!NO_ELSE_IN_WHEN!>when<!> (1) {
|
||||||
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!> -> 1 // not an expression
|
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!> -> 1 // not an expression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,4 +86,4 @@ class A1 {
|
|||||||
fun test() {
|
fun test() {
|
||||||
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>.equals(null)
|
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>.equals(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,12 +15,11 @@ fun testUnresolved() {
|
|||||||
foo1(<!UNRESOLVED_REFERENCE!>i<!>)
|
foo1(<!UNRESOLVED_REFERENCE!>i<!>)
|
||||||
s.<!UNRESOLVED_REFERENCE!>foo<!>()
|
s.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||||
|
|
||||||
when(<!UNRESOLVED_REFERENCE!>a<!>) {
|
<!NO_ELSE_IN_WHEN!>when<!>(<!UNRESOLVED_REFERENCE!>a<!>) {
|
||||||
is Int -> <!UNRESOLVED_REFERENCE!>a<!>
|
is Int -> <!UNRESOLVED_REFERENCE!>a<!>
|
||||||
is String -> <!UNRESOLVED_REFERENCE!>a<!>
|
is String -> <!UNRESOLVED_REFERENCE!>a<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
for (j in <!UNRESOLVED_REFERENCE!>collection<!>) {
|
for (j in <!UNRESOLVED_REFERENCE!>collection<!>) {
|
||||||
var i: Int = j
|
var i: Int = j
|
||||||
i += 1
|
i += 1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ fun foo() : Int {
|
|||||||
val s = ""
|
val s = ""
|
||||||
val x = 1
|
val x = 1
|
||||||
when (x) {
|
when (x) {
|
||||||
is * -> 1
|
|
||||||
is <!INCOMPATIBLE_TYPES!>String<!> -> 1
|
is <!INCOMPATIBLE_TYPES!>String<!> -> 1
|
||||||
!is Int -> 1
|
!is Int -> 1
|
||||||
is Any? -> 1
|
is Any? -> 1
|
||||||
@@ -16,7 +15,7 @@ fun foo() : Int {
|
|||||||
// Commented for KT-621 .<!!UNRESOLVED_REFERENCE!>a<!!> => 1
|
// Commented for KT-621 .<!!UNRESOLVED_REFERENCE!>a<!!> => 1
|
||||||
// Commented for KT-621 .equals(1).<!!UNRESOLVED_REFERENCE!>a<!!> => 1
|
// Commented for KT-621 .equals(1).<!!UNRESOLVED_REFERENCE!>a<!!> => 1
|
||||||
// Commented for KT-621 <!UNNECESSARY_SAFE_CALL!!>?.<!!>equals(1) => 1
|
// Commented for KT-621 <!UNNECESSARY_SAFE_CALL!!>?.<!!>equals(1) => 1
|
||||||
else -> 1
|
is * -> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commented for KT-621
|
// Commented for KT-621
|
||||||
@@ -34,7 +33,7 @@ fun test() {
|
|||||||
val x = 1;
|
val x = 1;
|
||||||
val s = "";
|
val s = "";
|
||||||
|
|
||||||
when (x) {
|
<!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||||
<!INCOMPATIBLE_TYPES!>s<!> -> 1
|
<!INCOMPATIBLE_TYPES!>s<!> -> 1
|
||||||
is <!INCOMPATIBLE_TYPES!>""<!> -> 1
|
is <!INCOMPATIBLE_TYPES!>""<!> -> 1
|
||||||
x -> 1
|
x -> 1
|
||||||
@@ -44,7 +43,7 @@ fun test() {
|
|||||||
|
|
||||||
val z = #(1, 1)
|
val z = #(1, 1)
|
||||||
|
|
||||||
when (z) {
|
<!NO_ELSE_IN_WHEN!>when<!> (z) {
|
||||||
is #(*, *) -> 1
|
is #(*, *) -> 1
|
||||||
is #(*, 1) -> 1
|
is #(*, 1) -> 1
|
||||||
is #(1, 1) -> 1
|
is #(1, 1) -> 1
|
||||||
@@ -55,8 +54,8 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (z) {
|
when (z) {
|
||||||
<!ELSE_MISPLACED_IN_WHEN!>else -> 1<!>
|
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> 1
|
||||||
#(1, 1) -> 2
|
<!UNREACHABLE_CODE!>#(1, 1) -> 2<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
when (z) {
|
when (z) {
|
||||||
@@ -64,4 +63,4 @@ fun test() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val #(Int, Int).boo : #(Int, Int, Int) = #(1, 1, 1)
|
val #(Int, Int).boo : #(Int, Int, Int) = #(1, 1, 1)
|
||||||
@@ -6,19 +6,19 @@ fun foo() : Int {
|
|||||||
var z = 0
|
var z = 0
|
||||||
when(d) {
|
when(d) {
|
||||||
is 5, is 3 -> <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, UNUSED_CHANGED_VALUE!>z++<!>
|
is 5, is 3 -> <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, UNUSED_CHANGED_VALUE!>z++<!>
|
||||||
<!ELSE_MISPLACED_IN_WHEN!>else -> { <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>z = <!UNUSED_VALUE!>-1000<!><!> }<!>
|
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> { <!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>z = <!UNUSED_VALUE!>-1000<!><!> }
|
||||||
return z -> <!UNREACHABLE_CODE!>34<!>
|
<!UNREACHABLE_CODE!>return z -> 34<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//test unreachable code
|
//test unreachable code
|
||||||
fun fff(): Int {
|
fun fff(): Int {
|
||||||
var d = 3
|
var d = 3
|
||||||
when(d) {
|
<!NO_ELSE_IN_WHEN!>when<!>(d) {
|
||||||
is 4 -> 21
|
is 4 -> 21
|
||||||
return 2 -> <!UNREACHABLE_CODE!>return 47<!>
|
return 2 -> <!UNREACHABLE_CODE!>return 47<!>
|
||||||
<!UNREACHABLE_CODE!>bar()<!> -> <!UNREACHABLE_CODE!>45<!>
|
<!UNREACHABLE_CODE!>bar() -> 45<!>
|
||||||
<!UNREACHABLE_CODE!>444<!> -> <!UNREACHABLE_CODE!>true<!>
|
<!UNREACHABLE_CODE!>444 -> true<!>
|
||||||
}
|
}
|
||||||
return 34
|
return 34
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//KT-234 Force when() expressions to have an 'else' branch
|
||||||
|
//KT-973 Unreachable code
|
||||||
|
|
||||||
|
package kt234_kt973
|
||||||
|
|
||||||
|
|
||||||
|
fun test(t : #(Int, Int)) : Int {
|
||||||
|
<!NO_ELSE_IN_WHEN!>when<!> (t) {
|
||||||
|
is #(10, 10) -> return 1
|
||||||
|
}
|
||||||
|
return 0 // unreachable code
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test1(t : #(Int, Int)) : Int {
|
||||||
|
when (t) {
|
||||||
|
is #(10, 10) -> return 1
|
||||||
|
else -> return 2
|
||||||
|
}
|
||||||
|
<!UNREACHABLE_CODE!>return 0<!> // unreachable code
|
||||||
|
}
|
||||||
|
|
||||||
|
//more tests
|
||||||
|
fun t1(x: Int) = when(x) {
|
||||||
|
is * -> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t2(x: Int) = when(x) {
|
||||||
|
is val a -> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t3(x: Int) = when (x) {
|
||||||
|
is * -> 1
|
||||||
|
<!UNREACHABLE_CODE!>2 -> 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t4(x: Int) = when (x) {
|
||||||
|
is val a -> 1
|
||||||
|
<!UNREACHABLE_CODE!>2 -> 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun t5(x: Int) = <!NO_ELSE_IN_WHEN!>when<!> (x) {
|
||||||
|
is val a : Int -> 1
|
||||||
|
2 -> 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo3(x: Int) = when(x) {
|
||||||
|
<!ELSE_MISPLACED_IN_WHEN!>else<!> -> 1
|
||||||
|
<!UNREACHABLE_CODE!>2 -> 2<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo4(x: Int) = when(x) {
|
||||||
|
2 -> x
|
||||||
|
is val a -> a
|
||||||
|
}
|
||||||
@@ -153,12 +153,12 @@ fun getStringLength(obj : Any) : Char? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun toInt(i: Int?): Int = if (i != null) i else 0
|
fun toInt(i: Int?): Int = if (i != null) i else 0
|
||||||
fun illegalWhenBody(a: Any): Int = when(a) {
|
fun illegalWhenBody(a: Any): Int = <!NO_ELSE_IN_WHEN!>when<!>(a) {
|
||||||
is Int -> a
|
is Int -> a
|
||||||
is String -> <!TYPE_MISMATCH!>a<!>
|
is String -> <!TYPE_MISMATCH!>a<!>
|
||||||
}
|
}
|
||||||
fun illegalWhenBlock(a: Any): Int {
|
fun illegalWhenBlock(a: Any): Int {
|
||||||
when(a) {
|
<!NO_ELSE_IN_WHEN!>when<!>(a) {
|
||||||
is Int -> return a
|
is Int -> return a
|
||||||
is String -> return <!TYPE_MISMATCH!>a<!>
|
is String -> return <!TYPE_MISMATCH!>a<!>
|
||||||
}
|
}
|
||||||
@@ -223,7 +223,7 @@ fun mergeAutocasts(a: Any?) {
|
|||||||
if (a is Int || a is String) {
|
if (a is Int || a is String) {
|
||||||
a.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
a.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||||
}
|
}
|
||||||
when (a) {
|
<!NO_ELSE_IN_WHEN!>when<!> (a) {
|
||||||
is String, is Any -> a.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
is String, is Any -> a.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||||
}
|
}
|
||||||
if (a is String && a is Any) {
|
if (a is String && a is Any) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
import jet.NoPatternMatchedException;
|
|
||||||
import jet.Tuple2;
|
import jet.Tuple2;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -25,7 +24,7 @@ public class PatternMatchingTest extends CodegenTestCase {
|
|||||||
loadFile();
|
loadFile();
|
||||||
Method foo = generateFunction();
|
Method foo = generateFunction();
|
||||||
assertTrue((Boolean) foo.invoke(null, 0));
|
assertTrue((Boolean) foo.invoke(null, 0));
|
||||||
assertThrows(foo, NoPatternMatchedException.class, null, 1);
|
assertThrows(foo, Exception.class, null, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPattern() throws Exception {
|
public void testPattern() throws Exception {
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ fun testUnresolved() {
|
|||||||
when(<error>a</error>) {
|
when(<error>a</error>) {
|
||||||
is Int -> <error>a</error>
|
is Int -> <error>a</error>
|
||||||
is String -> <error>a</error>
|
is String -> <error>a</error>
|
||||||
|
else -> <error>a</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO
|
|
||||||
for (j in <error>collection</error>) {
|
for (j in <error>collection</error>) {
|
||||||
var i: Int = j
|
var i: Int = j
|
||||||
i += 1
|
i += 1
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ fun foo() : Int {
|
|||||||
val s = ""
|
val s = ""
|
||||||
val x = 1
|
val x = 1
|
||||||
when (x) {
|
when (x) {
|
||||||
is * -> 1
|
|
||||||
is <error>String</error> -> 1
|
is <error>String</error> -> 1
|
||||||
!is Int -> 1
|
!is Int -> 1
|
||||||
is Any? -> 1
|
is Any? -> 1
|
||||||
@@ -16,7 +15,7 @@ fun foo() : Int {
|
|||||||
// Commented for KT-621 .<!error>a</!error> -> 1
|
// Commented for KT-621 .<!error>a</!error> -> 1
|
||||||
// Commented for KT-621 .equals(1).<!error>a</!error> -> 1
|
// Commented for KT-621 .equals(1).<!error>a</!error> -> 1
|
||||||
// Commented for KT-621 <!warning>?.</!warning>equals(1) -> 1
|
// Commented for KT-621 <!warning>?.</!warning>equals(1) -> 1
|
||||||
else -> 1
|
is * -> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commented for KT-621
|
// Commented for KT-621
|
||||||
@@ -39,6 +38,7 @@ fun test() {
|
|||||||
x -> 1
|
x -> 1
|
||||||
is 1 -> 1
|
is 1 -> 1
|
||||||
is <error>#(1, 1)</error> -> 1
|
is <error>#(1, 1)</error> -> 1
|
||||||
|
else -> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val z = #(1, 1)
|
val z = #(1, 1)
|
||||||
@@ -51,11 +51,12 @@ fun test() {
|
|||||||
is <error>#(1, "1", *)</error> -> 1
|
is <error>#(1, "1", *)</error> -> 1
|
||||||
is boo #(1, <error>"a"</error>, *) -> 1
|
is boo #(1, <error>"a"</error>, *) -> 1
|
||||||
is boo <error>#(1, *)</error> -> 1
|
is boo <error>#(1, *)</error> -> 1
|
||||||
|
else -> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
when (z) {
|
when (z) {
|
||||||
<error>else -> 1</error>
|
<error>else</error> -> 1
|
||||||
#(1, 1) -> 2
|
<error>#(1, 1) -> 2</error>
|
||||||
}
|
}
|
||||||
|
|
||||||
when (z) {
|
when (z) {
|
||||||
|
|||||||
@@ -154,11 +154,13 @@ fun toInt(i: Int?): Int = if (i != null) <info descr="Automatically cast to Int"
|
|||||||
fun illegalWhenBody(a: Any): Int = when(a) {
|
fun illegalWhenBody(a: Any): Int = when(a) {
|
||||||
is Int -> <info descr="Automatically cast to Int">a</info>
|
is Int -> <info descr="Automatically cast to Int">a</info>
|
||||||
is String -> <error descr="[TYPE_MISMATCH] Type mismatch: inferred type is Any but Int was expected">a</error>
|
is String -> <error descr="[TYPE_MISMATCH] Type mismatch: inferred type is Any but Int was expected">a</error>
|
||||||
|
else -> 1
|
||||||
}
|
}
|
||||||
fun illegalWhenBlock(a: Any): Int {
|
fun illegalWhenBlock(a: Any): Int {
|
||||||
when(a) {
|
when(a) {
|
||||||
is Int -> return <info descr="Automatically cast to Int">a</info>
|
is Int -> return <info descr="Automatically cast to Int">a</info>
|
||||||
is String -> return <error descr="[TYPE_MISMATCH] Type mismatch: inferred type is Any but Int was expected">a</error>
|
is String -> return <error descr="[TYPE_MISMATCH] Type mismatch: inferred type is Any but Int was expected">a</error>
|
||||||
|
else -> return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun declarations(a: Any?) {
|
fun declarations(a: Any?) {
|
||||||
@@ -221,7 +223,7 @@ fun mergeAutocasts(a: Any?) {
|
|||||||
if (a is Int || a is String) {
|
if (a is Int || a is String) {
|
||||||
a.<error descr="Unresolved reference: compareTo">compareTo</error>("")
|
a.<error descr="Unresolved reference: compareTo">compareTo</error>("")
|
||||||
}
|
}
|
||||||
when (a) {
|
<error>when</error> (a) {
|
||||||
is String, is Any -> a.<error descr="Unresolved reference: compareTo">compareTo</error>("")
|
is String, is Any -> a.<error descr="Unresolved reference: compareTo">compareTo</error>("")
|
||||||
}
|
}
|
||||||
if (a is String && a is Any) {
|
if (a is String && a is Any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user