Merge pull request #85 from udalov/kt2146

Kt2146
This commit is contained in:
Svetlana Isakova
2012-06-22 05:23:08 -07:00
5 changed files with 103 additions and 25 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -61,7 +62,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (pattern != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in 'is'");
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext());
newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, dataFlowValue);
newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, dataFlowValue).first;
context.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
}
@@ -87,38 +88,41 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
Set<JetType> expressionTypes = Sets.newHashSet();
DataFlowInfo commonDataFlowInfo = null;
DataFlowInfo elseDataFlowInfo = context.dataFlowInfo;
for (JetWhenEntry whenEntry : expression.getEntries()) {
JetWhenCondition[] conditions = whenEntry.getConditions();
DataFlowInfo newDataFlowInfo;
WritableScope scopeToExtend;
if (conditions.length == 1) {
if (whenEntry.isElse()) {
scopeToExtend = newWritableScopeImpl(context, "Scope extended in when-else entry");
newDataFlowInfo = elseDataFlowInfo;
}
else if (conditions.length == 1) {
scopeToExtend = newWritableScopeImpl(context, "Scope extended in when entry");
newDataFlowInfo = context.dataFlowInfo;
JetWhenCondition condition = conditions[0];
if (condition != null) {
newDataFlowInfo = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, scopeToExtend, context, variableDescriptor);
Pair<DataFlowInfo, DataFlowInfo> infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, scopeToExtend, context, variableDescriptor);
newDataFlowInfo = infos.first;
elseDataFlowInfo = elseDataFlowInfo.and(infos.second);
}
}
else {
scopeToExtend = newWritableScopeImpl(context, "pattern matching"); // We don't write to this scope
newDataFlowInfo = null;
for (JetWhenCondition condition : conditions) {
DataFlowInfo dataFlowInfo = checkWhenCondition(
subjectExpression, subjectExpression == null, subjectType, condition,
newWritableScopeImpl(context, ""), context, variableDescriptor);
Pair<DataFlowInfo, DataFlowInfo> infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, newWritableScopeImpl(context, ""), context, variableDescriptor);
if (newDataFlowInfo == null) {
newDataFlowInfo = dataFlowInfo;
newDataFlowInfo = infos.first;
}
else {
newDataFlowInfo = newDataFlowInfo.or(dataFlowInfo);
newDataFlowInfo = newDataFlowInfo.or(infos.first);
}
elseDataFlowInfo = elseDataFlowInfo.and(infos.second);
}
if (newDataFlowInfo == null) {
newDataFlowInfo = context.dataFlowInfo;
}
else {
newDataFlowInfo = newDataFlowInfo.and(context.dataFlowInfo);
}
}
JetExpression bodyExpression = whenEntry.getExpression();
if (bodyExpression != null) {
@@ -148,8 +152,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return JetTypeInfo.create(null, commonDataFlowInfo);
}
private DataFlowInfo checkWhenCondition(@Nullable final JetExpression subjectExpression, final boolean expectedCondition, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final ExpressionTypingContext context, final DataFlowValue... subjectVariables) {
final DataFlowInfo[] newDataFlowInfo = new DataFlowInfo[]{context.dataFlowInfo};
private Pair<DataFlowInfo, DataFlowInfo> checkWhenCondition(@Nullable final JetExpression subjectExpression, final boolean expectedCondition, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final ExpressionTypingContext context, final DataFlowValue... subjectVariables) {
final Ref<Pair<DataFlowInfo, DataFlowInfo>> newDataFlowInfo = new Ref<Pair<DataFlowInfo, DataFlowInfo>>(Pair.create(context.dataFlowInfo, context.dataFlowInfo));
condition.accept(new JetVisitorVoid() {
@Override
@@ -173,7 +177,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(EXPECTED_CONDITION.on(condition));
}
if (pattern != null) {
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
Pair<DataFlowInfo, DataFlowInfo> result = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
if (condition.isNegated()) {
newDataFlowInfo.set(Pair.create(result.second, result.first));
}
else {
newDataFlowInfo.set(result);
}
}
}
@@ -181,7 +191,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
JetPattern pattern = condition.getPattern();
if (pattern != null) {
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
newDataFlowInfo.set(checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables));
}
}
@@ -190,13 +200,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
}
});
return newDataFlowInfo[0];
return newDataFlowInfo.get();
}
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected,
private Pair<DataFlowInfo, DataFlowInfo> checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected,
@NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables
) {
final Ref<DataFlowInfo> result = new Ref<DataFlowInfo>(context.dataFlowInfo);
final Ref<Pair<DataFlowInfo, DataFlowInfo>> result = new Ref<Pair<DataFlowInfo, DataFlowInfo>>(Pair.create(context.dataFlowInfo, context.dataFlowInfo));
pattern.accept(new JetVisitorVoid() {
@Override
public void visitTypePattern(JetTypePattern typePattern) {
@@ -204,7 +214,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
if (typeReference == null) return;
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
checkTypeCompatibility(type, subjectType, typePattern);
result.set(context.dataFlowInfo.establishSubtyping(subjectVariables, type));
result.set(Pair.create(context.dataFlowInfo.establishSubtyping(subjectVariables, type), context.dataFlowInfo));
}
@Override
@@ -229,7 +239,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
JetPattern entryPattern = entry.getPattern();
if (entryPattern != null) {
result.set(result.get().and(checkPatternType(entryPattern, type, false, scopeToExtend, context)));
Pair<DataFlowInfo, DataFlowInfo> dataFlowInfos = checkPatternType(entryPattern, type, false, scopeToExtend, context);
result.set(Pair.create(result.get().first.and(dataFlowInfos.first), context.dataFlowInfo));
}
}
}
@@ -258,15 +269,29 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
public void visitExpressionPattern(JetExpressionPattern pattern) {
JetExpression expression = pattern.getExpression();
if (expression == null) return;
JetType type = facade.getTypeInfo(expression, context.replaceScope(scopeToExtend)).getType();
JetTypeInfo typeInfo = facade.getTypeInfo(expression, context.replaceScope(scopeToExtend));
JetType type = typeInfo.getType();
if (type == null) return;
if (conditionExpected) {
JetType booleanType = JetStandardLibrary.getInstance().getBooleanType();
if (type != null && !JetTypeChecker.INSTANCE.equalTypes(booleanType, type)) {
if (!JetTypeChecker.INSTANCE.equalTypes(booleanType, type)) {
context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(pattern, type));
}
else {
DataFlowInfo ifInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, true, scopeToExtend, context);
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, false, null, context);
result.set(Pair.create(ifInfo, elseInfo));
}
return;
}
checkTypeCompatibility(type, subjectType, pattern);
DataFlowValue expressionDataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, type, context.trace.getBindingContext());
for (DataFlowValue subjectVariable : subjectVariables) {
result.set(Pair.create(
result.get().first.equate(subjectVariable, expressionDataFlowValue),
result.get().second.disequate(subjectVariable, expressionDataFlowValue)
));
}
}
@Override
@@ -11,7 +11,7 @@ fun foo() {
}
when (x) {
0 -> { if (x == null) return }
0 -> { if (<!SENSELESS_COMPARISON!>x == null<!>) return }
else -> { if (x == null) return }
}
bar(x)
@@ -0,0 +1,53 @@
//KT-2146 Nullability casts in when.
package kt2146
fun f1(s: Int?): Int {
return when (s) {
null -> 3
else -> s
}
}
fun f2(s: Int?): Int {
return when (s) {
!is Int -> <!TYPE_MISMATCH!>s<!>
else -> s
}
}
fun f3(s: Int?): Int {
return when (s) {
is Int -> s
else -> <!TYPE_MISMATCH!>s<!>
}
}
fun f4(s: Int?): Int {
return when {
s == 4 -> s
s == null -> <!TYPE_MISMATCH!>s<!>
else -> s
}
}
fun f5(s: Int?): Int {
return when (s) {
s!! -> s
s -> <!TYPE_MISMATCH!>s<!>
else -> 0
}
}
fun f6(s: Int?): Int {
return when {
s is Int -> s
else -> <!TYPE_MISMATCH!>s<!>
}
}
fun f7(s: Int?): Int {
return when {
s !is Int -> <!TYPE_MISMATCH!>s<!>
else -> s
}
}
@@ -1,7 +1,7 @@
fun set(<!UNUSED_PARAMETER!>key<!> : String, <!UNUSED_PARAMETER!>value<!> : String) {
val a : String? = ""
when (a) {
"" -> a<!UNSAFE_CALL!>.<!>get(0)
"" -> a.get(0)
is String, is Any -> a.compareTo("")
else -> a.toString()
}
+1 -1
View File
@@ -1,7 +1,7 @@
fun set(<warning>key</warning> : String, <warning>value</warning> : String) {
val a : String? = ""
when (a) {
"" -> a<error>.</error>get(0)
"" -> a.get(0)
is String, is Any -> a.compareTo("")
else -> a.toString()
}