Basic support for when() expressions
This commit is contained in:
@@ -16,7 +16,7 @@ whenConditionIf
|
||||
|
||||
whenCondition
|
||||
: expression
|
||||
: "." postfixUnaryExpression typeArguments? valueArguments?
|
||||
: ("." | "?.") postfixUnaryExpression typeArguments? valueArguments?
|
||||
: ("in" | "!in") expression
|
||||
: ("is" | "!is") isRHS
|
||||
;
|
||||
|
||||
@@ -111,22 +111,22 @@ public interface JetNodeTypes {
|
||||
JetNodeType HASH_QUALIFIED_EXPRESSION = new JetNodeType("HASH_QUALIFIED_EXPRESSION", JetHashQualifiedExpression.class);
|
||||
JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class);
|
||||
JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class);
|
||||
JetNodeType DECOMPOSER_PATTERN = new JetNodeType("DECOMPOSER_PATTERN");
|
||||
JetNodeType TUPLE_PATTERN = new JetNodeType("TUPLE_PATTERN");
|
||||
JetNodeType DECOMPOSER_PATTERN = new JetNodeType("DECOMPOSER_PATTERN", JetPattern.class); // TODO
|
||||
JetNodeType TUPLE_PATTERN = new JetNodeType("TUPLE_PATTERN", JetPattern.class); // TODO
|
||||
JetNodeType OBJECT_LITERAL = new JetNodeType("OBJECT_LITERAL", JetObjectLiteralExpression.class);
|
||||
JetNodeType ROOT_NAMESPACE = new JetNodeType("ROOT_NAMESPACE", JetRootNamespaceExpression.class);
|
||||
JetNodeType DECOMPOSER_ARGUMENT_LIST = new JetNodeType("DECOMPOSER_ARGUMENT_LIST");
|
||||
JetNodeType DECOMPOSER_ARGUMENT = new JetNodeType("DECOMPOSER_ARGUMENT");
|
||||
JetNodeType TYPE_PATTERN = new JetNodeType("TYPE_PATTERN", JetTypePattern.class);
|
||||
JetNodeType EXPRESSION_PATTERN = new JetNodeType("EXPRESSION_PATTERN");
|
||||
JetNodeType BINDING_PATTERN = new JetNodeType("BINDING_PATTERN");
|
||||
JetNodeType WILDCARD_PATTERN = new JetNodeType("WILDCARD_PATTERN");
|
||||
JetNodeType EXPRESSION_PATTERN = new JetNodeType("EXPRESSION_PATTERN", JetPattern.class); // TODO
|
||||
JetNodeType BINDING_PATTERN = new JetNodeType("BINDING_PATTERN", JetPattern.class); // TODO
|
||||
JetNodeType WILDCARD_PATTERN = new JetNodeType("WILDCARD_PATTERN", JetPattern.class); // TODO
|
||||
JetNodeType WHEN = new JetNodeType("WHEN", JetWhenExpression.class);
|
||||
JetNodeType WHEN_ENTRY = new JetNodeType("WHEN_ENTRY", JetWhenEntry.class);
|
||||
JetNodeType WHEN_CONDITION_IN_RANGE = new JetNodeType("WHEN_CONDITION_IN_RANGE");
|
||||
JetNodeType WHEN_CONDITION_IS_PATTERN = new JetNodeType("WHEN_CONDITION_IS_PATTERN");
|
||||
JetNodeType WHEN_CONDITION_CALL = new JetNodeType("WHEN_CONDITION_CALL");
|
||||
JetNodeType WHEN_CONDITION_EXPRESSION = new JetNodeType("WHEN_CONDITION_EXPRESSION");
|
||||
JetNodeType WHEN_CONDITION_IN_RANGE = new JetNodeType("WHEN_CONDITION_IN_RANGE", JetWhenConditionInRange.class);
|
||||
JetNodeType WHEN_CONDITION_IS_PATTERN = new JetNodeType("WHEN_CONDITION_IS_PATTERN", JetWhenConditionIsPattern.class);
|
||||
JetNodeType WHEN_CONDITION_CALL = new JetNodeType("WHEN_CONDITION_CALL", JetWhenConditionCall.class);
|
||||
JetNodeType WHEN_CONDITION_EXPRESSION = new JetNodeType("WHEN_CONDITION_EXPRESSION", JetWhenConditionWithExpression.class);
|
||||
JetNodeType TUPLE_PATTERN_ENTRY = new JetNodeType("TUPLE_PATTERN_ENTRY");
|
||||
JetNodeType NULLABLE_TYPE = new JetNodeType("NULLABLE_TYPE", JetNullableType.class);
|
||||
JetNodeType TYPE_PROJECTION = new JetNodeType("TYPE_PROJECTION", JetTypeProjection.class);
|
||||
|
||||
@@ -96,7 +96,8 @@ public class JetControlFlowProcessor {
|
||||
this.inCondition = inCondition;
|
||||
}
|
||||
|
||||
private void value(@NotNull JetElement element, boolean preferBlock, boolean inCondition) {
|
||||
private void value(@Nullable JetElement element, boolean preferBlock, boolean inCondition) {
|
||||
if (element == null) return;
|
||||
CFPVisitor visitor;
|
||||
if (this.preferBlock == preferBlock && this.inCondition == inCondition) {
|
||||
visitor = this;
|
||||
@@ -609,6 +610,61 @@ public class JetControlFlowProcessor {
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenExpression(JetWhenExpression expression) {
|
||||
// TODO : no more than one else
|
||||
// TODO : else must be the last
|
||||
JetExpression subjectExpression = expression.getSubjectExpression();
|
||||
if (subjectExpression != null) {
|
||||
value(subjectExpression, false, inCondition);
|
||||
}
|
||||
|
||||
Label nextLabel = builder.createUnboundLabel();
|
||||
for (JetWhenEntry whenEntry : expression.getEntries()) {
|
||||
if (whenEntry.getSubWhen() != null) throw new UnsupportedOperationException(); // TODO
|
||||
|
||||
if (whenEntry.isElseContinue()) throw new UnsupportedOperationException(); // TODO
|
||||
|
||||
JetWhenCondition condition = whenEntry.getCondition();
|
||||
if (condition != null) {
|
||||
condition.accept(new JetVisitor() {
|
||||
@Override
|
||||
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
|
||||
value(condition.getExpression(), false, inCondition); // TODO : inCondition?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
value(condition.getCallSuffixExpression(), false, inCondition); // TODO : inCondition?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
value(condition.getRangeExpression(), false, inCondition); // TODO : inCondition?
|
||||
value(condition.getOperationReference(), false, inCondition); // TODO : inCondition?
|
||||
// TODO : read the call to contains()...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
super.visitWhenConditionIsPattern(condition); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement elem) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
builder.nondeterministicJump(nextLabel);
|
||||
|
||||
value(whenEntry.getExpression(), true, inCondition);
|
||||
builder.bindLabel(nextLabel);
|
||||
nextLabel = builder.createUnboundLabel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeProjection(JetTypeProjection typeProjection) {
|
||||
// TODO : Support Type Arguments. Class object may be initialized at this point");
|
||||
|
||||
@@ -706,7 +706,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
/*
|
||||
* whenCondition
|
||||
* : expression
|
||||
* : "." postfixExpression typeArguments? valueArguments?
|
||||
* : ("." | "?." postfixExpression typeArguments? valueArguments?
|
||||
* : ("in" | "!in") expression
|
||||
* : ("is" | "!is") isRHS
|
||||
* ;
|
||||
@@ -715,7 +715,10 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
PsiBuilder.Marker condition = mark();
|
||||
myBuilder.disableNewlines();
|
||||
if (at(IN_KEYWORD) || at(NOT_IN)) {
|
||||
PsiBuilder.Marker mark = mark();
|
||||
advance(); // IN_KEYWORD or NOT_IN
|
||||
mark.done(OPERATION_REFERENCE);
|
||||
|
||||
|
||||
if (atSet(WHEN_CONDITION_RECOVERY_SET_WITH_DOUBLE_ARROW)) {
|
||||
error("Expecting an element");
|
||||
@@ -732,13 +735,20 @@ public class JetExpressionParsing extends AbstractJetParsing {
|
||||
parsePattern();
|
||||
}
|
||||
condition.done(WHEN_CONDITION_IS_PATTERN);
|
||||
} else if (at(DOT)) {
|
||||
advance(); // DOT
|
||||
} else if (at(DOT) || at(SAFE_ACCESS)) {
|
||||
advance(); // DOT or SAFE_ACCESS
|
||||
PsiBuilder.Marker mark = mark();
|
||||
parsePostfixExpression();
|
||||
myJetParsing.parseTypeArgumentList();
|
||||
if (at(LPAR)) {
|
||||
parseValueArgumentList();
|
||||
if (parseCallSuffix()) {
|
||||
mark.done(CALL_EXPRESSION);
|
||||
}
|
||||
else {
|
||||
mark.drop();
|
||||
}
|
||||
// myJetParsing.parseTypeArgumentList();
|
||||
// if (at(LPAR)) {
|
||||
// parseValueArgumentList();
|
||||
// }
|
||||
condition.done(WHEN_CONDITION_CALL);
|
||||
} else {
|
||||
if (atSet(WHEN_CONDITION_RECOVERY_SET_WITH_DOUBLE_ARROW)) {
|
||||
|
||||
@@ -349,4 +349,20 @@ public class JetVisitor extends PsiElementVisitor {
|
||||
public void visitIsExpression(JetIsExpression expression) {
|
||||
visitExpression(expression);
|
||||
}
|
||||
|
||||
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
|
||||
visitJetElement(condition);
|
||||
}
|
||||
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
visitJetElement(condition);
|
||||
}
|
||||
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
visitJetElement(condition);
|
||||
}
|
||||
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
visitJetElement(condition);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public abstract class JetWhenCondition extends JetElement {
|
||||
public JetWhenCondition(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetWhenConditionCall extends JetWhenCondition {
|
||||
public JetWhenConditionCall(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public boolean isSafeCall() {
|
||||
return getNode().findChildByType(JetTokens.SAFE_ACCESS) != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ASTNode getOperationTokenNode() {
|
||||
return getNode().findChildByType(TokenSet.create(JetTokens.SAFE_ACCESS, JetTokens.DOT));
|
||||
}
|
||||
|
||||
@Nullable @IfNotParsed
|
||||
public JetExpression getCallSuffixExpression() {
|
||||
return findChildByClass(JetExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull JetVisitor visitor) {
|
||||
visitor.visitWhenConditionCall(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetWhenConditionInRange extends JetWhenCondition {
|
||||
public JetWhenConditionInRange(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public boolean isNegated() {
|
||||
return getNode().findChildByType(JetTokens.NOT_IN) != null;
|
||||
}
|
||||
|
||||
@Nullable @IfNotParsed
|
||||
public JetExpression getRangeExpression() {
|
||||
// Copied from JetBinaryExpression
|
||||
ASTNode node = getOperationReference().getNode().getTreeNext();
|
||||
while (node != null) {
|
||||
PsiElement psi = node.getPsi();
|
||||
if (psi instanceof JetExpression) {
|
||||
return (JetExpression) psi;
|
||||
}
|
||||
node = node.getTreeNext();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull JetVisitor visitor) {
|
||||
visitor.visitWhenConditionInRange(this);
|
||||
}
|
||||
|
||||
public JetSimpleNameExpression getOperationReference() {
|
||||
return (JetSimpleNameExpression) findChildByType(JetNodeTypes.OPERATION_REFERENCE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetWhenConditionIsPattern extends JetWhenCondition {
|
||||
public JetWhenConditionIsPattern(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public boolean isNegated() {
|
||||
return getNode().findChildByType(JetTokens.NOT_IS) != null;
|
||||
}
|
||||
|
||||
@Nullable @IfNotParsed
|
||||
public JetPattern getPattern() {
|
||||
return findChildByClass(JetPattern.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull JetVisitor visitor) {
|
||||
visitor.visitWhenConditionIsPattern(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetWhenConditionWithExpression extends JetWhenCondition {
|
||||
public JetWhenConditionWithExpression(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@IfNotParsed
|
||||
public JetExpression getExpression() {
|
||||
return findChildByClass(JetExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull JetVisitor visitor) {
|
||||
visitor.visitWhenConditionWithExpression(this);
|
||||
}
|
||||
}
|
||||
@@ -37,4 +37,9 @@ public class JetWhenEntry extends JetElement {
|
||||
public void accept(@NotNull JetVisitor visitor) {
|
||||
visitor.visitWhenEntry(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetWhenCondition getCondition() {
|
||||
return findChildByClass(JetWhenCondition.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
|
||||
import java.util.List;
|
||||
@@ -19,6 +20,11 @@ public class JetWhenExpression extends JetExpression {
|
||||
return findChildrenByType(JetNodeTypes.WHEN_ENTRY);
|
||||
}
|
||||
|
||||
@Nullable @IfNotParsed
|
||||
public JetExpression getSubjectExpression() {
|
||||
return findChildByClass(JetExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(JetVisitor visitor) {
|
||||
visitor.visitWhenExpression(this);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.jet.lang.types;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -151,7 +152,7 @@ public class JetTypeInferrer {
|
||||
public void visitQualifiedExpression(JetQualifiedExpression expression) {
|
||||
// . or ?.
|
||||
JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
|
||||
checkNullSafety(receiverType, expression);
|
||||
checkNullSafety(receiverType, expression.getOperationTokenNode());
|
||||
|
||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||
if (selectorExpression instanceof JetSimpleNameExpression) {
|
||||
@@ -191,19 +192,20 @@ public class JetTypeInferrer {
|
||||
return wrapForTracing(result[0], reference[0], argumentList, true);
|
||||
}
|
||||
|
||||
private void checkNullSafety(JetType receiverType, JetQualifiedExpression expression) {
|
||||
private void checkNullSafety(JetType receiverType, ASTNode operationTokenNode) {
|
||||
if (receiverType != null) {
|
||||
boolean namespaceType = receiverType instanceof NamespaceType;
|
||||
boolean nullable = !namespaceType && receiverType.isNullable();
|
||||
if (nullable && expression.getOperationSign() == JetTokens.DOT) {
|
||||
trace.getErrorHandler().genericError(expression.getOperationTokenNode(), "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
|
||||
IElementType operationSign = operationTokenNode.getElementType();
|
||||
if (nullable && operationSign == JetTokens.DOT) {
|
||||
trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
|
||||
}
|
||||
else if (!nullable && expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
||||
else if (!nullable && operationSign == JetTokens.SAFE_ACCESS) {
|
||||
if (namespaceType) {
|
||||
trace.getErrorHandler().genericError(expression.getOperationTokenNode(), "Safe calls are not allowed on namespaces");
|
||||
trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces");
|
||||
}
|
||||
else {
|
||||
trace.getErrorHandler().genericWarning(expression.getOperationTokenNode(), "Unnecessary safe call on a non-null receiver of type " + receiverType);
|
||||
trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,7 +380,10 @@ public class JetTypeInferrer {
|
||||
} else {
|
||||
JetExpression resultExpression = entry.getExpression();
|
||||
if (resultExpression != null) {
|
||||
result.add(getType(scope, resultExpression, true));
|
||||
JetType type = getType(scope, resultExpression, true);
|
||||
if (type != null) {
|
||||
result.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -964,11 +969,75 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenExpression(JetWhenExpression expression) {
|
||||
public void visitWhenExpression(final JetWhenExpression expression) {
|
||||
// TODO :change scope according to the bound value in the when header
|
||||
List<JetType> expressions = new ArrayList<JetType>();
|
||||
collectAllReturnTypes(expression, scope, expressions);
|
||||
result = semanticServices.getTypeChecker().commonSupertype(expressions);
|
||||
final JetExpression subjectExpression = expression.getSubjectExpression();
|
||||
|
||||
JetType subjectType = null;
|
||||
if (subjectExpression != null) {
|
||||
subjectType = getType(scope, subjectExpression, false);
|
||||
}
|
||||
|
||||
// TODO : exhaustive patterns
|
||||
|
||||
for (JetWhenEntry whenEntry : expression.getEntries()) {
|
||||
final JetType finalSubjectType = subjectType;
|
||||
JetWhenCondition condition = whenEntry.getCondition();
|
||||
if (condition != null) {
|
||||
condition.accept(new JetVisitor() {
|
||||
@Override
|
||||
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
|
||||
JetExpression conditionExpression = condition.getExpression();
|
||||
if (conditionExpression != null) {
|
||||
JetType type = getType(scope, conditionExpression, false);
|
||||
if (type != null && finalSubjectType != null) {
|
||||
if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(finalSubjectType, type)) == null) {
|
||||
trace.getErrorHandler().genericError(conditionExpression.getNode(), "This condition can never hold");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
checkNullSafety(finalSubjectType, condition.getOperationTokenNode());
|
||||
JetExpression callSuffixExpression = condition.getCallSuffixExpression();
|
||||
JetScope compositeScope = new ScopeWithReceiver(scope, finalSubjectType);
|
||||
if (callSuffixExpression != null) {
|
||||
JetType selectorReturnType = getType(compositeScope, callSuffixExpression, false);
|
||||
ensureBooleanResultWithCustomSubject(callSuffixExpression, selectorReturnType, "This expression");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
JetExpression rangeExpression = condition.getRangeExpression();
|
||||
if (rangeExpression != null) {
|
||||
checkInExpression(condition.getOperationReference(), subjectExpression, rangeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
super.visitWhenConditionIsPattern(condition); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement elem) {
|
||||
trace.getErrorHandler().genericError(elem.getNode(), "Unsupported [JetTypeInferrer] : " + elem);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
List<JetType> expressionTypes = new ArrayList<JetType>();
|
||||
collectAllReturnTypes(expression, scope, expressionTypes);
|
||||
if (!expressionTypes.isEmpty()) {
|
||||
result = semanticServices.getTypeChecker().commonSupertype(expressionTypes);
|
||||
}
|
||||
else {
|
||||
trace.getErrorHandler().genericError(expression.getNode(), "Entries required for when-expression"); // TODO : Scope, and maybe this should not an error
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1226,10 +1295,10 @@ public class JetTypeInferrer {
|
||||
JetExpression receiverExpression = expression.getReceiverExpression();
|
||||
JetType receiverType = new TypeInferrerVisitorWithNamespaces(scope, false).getType(receiverExpression);
|
||||
if (receiverType != null) {
|
||||
checkNullSafety(receiverType, expression);
|
||||
checkNullSafety(receiverType, expression.getOperationTokenNode());
|
||||
JetType selectorReturnType = getSelectorReturnType(receiverType, selectorExpression);
|
||||
if (expression.getOperationSign() == JetTokens.QUEST) {
|
||||
if (selectorReturnType != null && !isBoolean(selectorReturnType)) {
|
||||
if (selectorReturnType != null && !isBoolean(selectorReturnType) && selectorExpression != null) {
|
||||
// TODO : more comprehensible error message
|
||||
trace.getErrorHandler().typeMismatch(selectorExpression, semanticServices.getStandardLibrary().getBooleanType(), selectorReturnType);
|
||||
}
|
||||
@@ -1395,9 +1464,7 @@ public class JetTypeInferrer {
|
||||
result = ErrorUtils.createErrorType("No right argument"); // TODO
|
||||
return;
|
||||
}
|
||||
String name = "contains";
|
||||
JetType containsType = getTypeForBinaryCall(scope, right, expression.getOperationReference(), expression.getLeft(), name, true);
|
||||
ensureBooleanResult(operationSign, name, containsType);
|
||||
checkInExpression(operationSign, left, right);
|
||||
result = semanticServices.getStandardLibrary().getBooleanType();
|
||||
}
|
||||
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
|
||||
@@ -1428,6 +1495,12 @@ public class JetTypeInferrer {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right) {
|
||||
String name = "contains";
|
||||
JetType containsType = getTypeForBinaryCall(scope, right, operationSign, left, name, true);
|
||||
ensureBooleanResult(operationSign, name, containsType);
|
||||
}
|
||||
|
||||
private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression) {
|
||||
JetSimpleNameExpression operationSign = expression.getOperationReference();
|
||||
JetExpression left = expression.getLeft();
|
||||
@@ -1459,11 +1532,15 @@ public class JetTypeInferrer {
|
||||
trace.getErrorHandler().genericError(expression.getNode(), "Assignments are not expressions, and only expressions are allowed in this context");
|
||||
}
|
||||
|
||||
private boolean ensureBooleanResult(JetSimpleNameExpression operationSign, String name, JetType resultType) {
|
||||
private boolean ensureBooleanResult(JetExpression operationSign, String name, JetType resultType) {
|
||||
return ensureBooleanResultWithCustomSubject(operationSign, resultType, "'" + name + "'");
|
||||
}
|
||||
|
||||
private boolean ensureBooleanResultWithCustomSubject(JetExpression operationSign, JetType resultType, String subjectName) {
|
||||
if (resultType != null) {
|
||||
// TODO : Relax?
|
||||
if (!isBoolean(resultType)) {
|
||||
trace.getErrorHandler().genericError(operationSign.getNode(), "'" + name + "' must return Boolean but returns " + resultType);
|
||||
trace.getErrorHandler().genericError(operationSign.getNode(), subjectName + " must return Boolean but returns " + resultType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
fun foo() {
|
||||
val s = ""
|
||||
val x = 1
|
||||
when (x) {
|
||||
<error>s</error> => 1
|
||||
1 => 1
|
||||
1 + <error>a</error> => 1
|
||||
in 1..<error>a</error> => 1
|
||||
!in 1..<error>a</error> => 1
|
||||
.<error>a</error> => 1
|
||||
.equals(1).<error>a</error> => 1
|
||||
<warning>?.</warning>equals(1) => 1
|
||||
}
|
||||
when (<warning>x</warning>?:null) {
|
||||
<error>.</error>equals(1) => 1
|
||||
?.equals(1).equals(2) => 1
|
||||
}
|
||||
}
|
||||
@@ -254,7 +254,8 @@ JetFile: NewlinesInParentheses.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(in)('in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(in)('in')
|
||||
PsiWhiteSpace(' ')
|
||||
CALL_EXPRESSION
|
||||
REFERENCE_EXPRESSION
|
||||
@@ -290,7 +291,8 @@ JetFile: NewlinesInParentheses.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
PsiWhiteSpace(' ')
|
||||
CALL_EXPRESSION
|
||||
REFERENCE_EXPRESSION
|
||||
|
||||
@@ -755,7 +755,8 @@ JetFile: When.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(in)('in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(in)('in')
|
||||
PsiWhiteSpace(' ')
|
||||
BINARY_EXPRESSION
|
||||
INTEGER_CONSTANT
|
||||
@@ -772,7 +773,8 @@ JetFile: When.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
PsiWhiteSpace(' ')
|
||||
INTEGER_CONSTANT
|
||||
PsiElement(INTEGER_LITERAL)('2')
|
||||
|
||||
@@ -59,7 +59,8 @@ JetFile: When_ERR.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(in)('in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(in)('in')
|
||||
PsiErrorElement:Expecting an element
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
@@ -70,7 +71,8 @@ JetFile: When_ERR.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
PsiErrorElement:Expecting an element
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
@@ -127,7 +129,8 @@ JetFile: When_ERR.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(in)('in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(in)('in')
|
||||
PsiErrorElement:Expecting an element
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
@@ -137,7 +140,8 @@ JetFile: When_ERR.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
PsiErrorElement:Expecting an element
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
@@ -147,7 +151,8 @@ JetFile: When_ERR.jet
|
||||
PsiWhiteSpace('\n ')
|
||||
WHEN_ENTRY
|
||||
WHEN_CONDITION_IN_RANGE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
OPERATION_REFERENCE
|
||||
PsiElement(NOT_IN)('!in')
|
||||
PsiErrorElement:Expecting an element
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
|
||||
Reference in New Issue
Block a user