KT-2146 Nullability casts in when.
#KT-2146 Fixed
This commit is contained in:
+29
-20
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types.expressions;
|
|||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -61,7 +62,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (pattern != null) {
|
if (pattern != null) {
|
||||||
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in 'is'");
|
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in 'is'");
|
||||||
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext());
|
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.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
|
||||||
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
|
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
|
||||||
}
|
}
|
||||||
@@ -87,31 +88,37 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
Set<JetType> expressionTypes = Sets.newHashSet();
|
Set<JetType> expressionTypes = Sets.newHashSet();
|
||||||
DataFlowInfo commonDataFlowInfo = null;
|
DataFlowInfo commonDataFlowInfo = null;
|
||||||
|
DataFlowInfo elseDataFlowInfo = context.dataFlowInfo;
|
||||||
for (JetWhenEntry whenEntry : expression.getEntries()) {
|
for (JetWhenEntry whenEntry : expression.getEntries()) {
|
||||||
JetWhenCondition[] conditions = whenEntry.getConditions();
|
JetWhenCondition[] conditions = whenEntry.getConditions();
|
||||||
DataFlowInfo newDataFlowInfo;
|
DataFlowInfo newDataFlowInfo;
|
||||||
WritableScope scopeToExtend;
|
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");
|
scopeToExtend = newWritableScopeImpl(context, "Scope extended in when entry");
|
||||||
newDataFlowInfo = context.dataFlowInfo;
|
newDataFlowInfo = context.dataFlowInfo;
|
||||||
JetWhenCondition condition = conditions[0];
|
JetWhenCondition condition = conditions[0];
|
||||||
if (condition != null) {
|
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 {
|
else {
|
||||||
scopeToExtend = newWritableScopeImpl(context, "pattern matching"); // We don't write to this scope
|
scopeToExtend = newWritableScopeImpl(context, "pattern matching"); // We don't write to this scope
|
||||||
newDataFlowInfo = null;
|
newDataFlowInfo = null;
|
||||||
for (JetWhenCondition condition : conditions) {
|
for (JetWhenCondition condition : conditions) {
|
||||||
DataFlowInfo dataFlowInfo = checkWhenCondition(
|
Pair<DataFlowInfo, DataFlowInfo> infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, newWritableScopeImpl(context, ""), context, variableDescriptor);
|
||||||
subjectExpression, subjectExpression == null, subjectType, condition,
|
|
||||||
newWritableScopeImpl(context, ""), context, variableDescriptor);
|
|
||||||
if (newDataFlowInfo == null) {
|
if (newDataFlowInfo == null) {
|
||||||
newDataFlowInfo = dataFlowInfo;
|
newDataFlowInfo = infos.first;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
newDataFlowInfo = newDataFlowInfo.or(dataFlowInfo);
|
newDataFlowInfo = newDataFlowInfo.or(infos.first);
|
||||||
}
|
}
|
||||||
|
elseDataFlowInfo = elseDataFlowInfo.and(infos.second);
|
||||||
}
|
}
|
||||||
if (newDataFlowInfo == null) {
|
if (newDataFlowInfo == null) {
|
||||||
newDataFlowInfo = context.dataFlowInfo;
|
newDataFlowInfo = context.dataFlowInfo;
|
||||||
@@ -145,8 +152,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return JetTypeInfo.create(null, commonDataFlowInfo);
|
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) {
|
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 DataFlowInfo[] newDataFlowInfo = new DataFlowInfo[]{context.dataFlowInfo};
|
final Ref<Pair<DataFlowInfo, DataFlowInfo>> newDataFlowInfo = new Ref<Pair<DataFlowInfo, DataFlowInfo>>(Pair.create(context.dataFlowInfo, context.dataFlowInfo));
|
||||||
condition.accept(new JetVisitorVoid() {
|
condition.accept(new JetVisitorVoid() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -170,7 +177,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
context.trace.report(EXPECTED_CONDITION.on(condition));
|
context.trace.report(EXPECTED_CONDITION.on(condition));
|
||||||
}
|
}
|
||||||
if (pattern != null) {
|
if (pattern != null) {
|
||||||
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
|
newDataFlowInfo.set(checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +185,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
|
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
|
||||||
JetPattern pattern = condition.getPattern();
|
JetPattern pattern = condition.getPattern();
|
||||||
if (pattern != null) {
|
if (pattern != null) {
|
||||||
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
|
newDataFlowInfo.set(checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,13 +194,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
|
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
|
@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() {
|
pattern.accept(new JetVisitorVoid() {
|
||||||
@Override
|
@Override
|
||||||
public void visitTypePattern(JetTypePattern typePattern) {
|
public void visitTypePattern(JetTypePattern typePattern) {
|
||||||
@@ -201,7 +208,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
if (typeReference == null) return;
|
if (typeReference == null) return;
|
||||||
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
|
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
|
||||||
checkTypeCompatibility(type, subjectType, typePattern);
|
checkTypeCompatibility(type, subjectType, typePattern);
|
||||||
result.set(context.dataFlowInfo.establishSubtyping(subjectVariables, type));
|
result.set(Pair.create(context.dataFlowInfo.establishSubtyping(subjectVariables, type), context.dataFlowInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,7 +233,8 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
JetPattern entryPattern = entry.getPattern();
|
JetPattern entryPattern = entry.getPattern();
|
||||||
if (entryPattern != null) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,12 +273,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkTypeCompatibility(type, subjectType, pattern);
|
checkTypeCompatibility(type, subjectType, pattern);
|
||||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
|
||||||
DataFlowValue expressionDataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, type, context.trace.getBindingContext());
|
DataFlowValue expressionDataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, type, context.trace.getBindingContext());
|
||||||
for (DataFlowValue subjectVariable : subjectVariables) {
|
for (DataFlowValue subjectVariable : subjectVariables) {
|
||||||
dataFlowInfo = dataFlowInfo.equate(subjectVariable, expressionDataFlowValue);
|
result.set(Pair.create(
|
||||||
|
result.get().first.equate(subjectVariable, expressionDataFlowValue),
|
||||||
|
result.get().second.disequate(subjectVariable, expressionDataFlowValue)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
result.set(dataFlowInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//KT-2146 Nullability casts in when.
|
||||||
|
package kt2146
|
||||||
|
|
||||||
|
fun f(s : Int?) : Int {
|
||||||
|
return when (s) {
|
||||||
|
null -> 3
|
||||||
|
else -> s // type mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user