DataFlowInfo treatment adjusted for absence of complex patterns

As patterns in when are no longer recursively nested, teh code is simplified.
Also, instead of keeing a Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo in ExpressionTypingContext,
we fall back for a slice in the trace.

Refactoring: DataFlowInfos class introduced to repace a Pair<DFI, DFI>

 #KT-2359 In Progress
This commit is contained in:
Andrey Breslav
2012-09-05 12:52:31 +04:00
parent 70f3da109d
commit 756ca9b284
5 changed files with 135 additions and 205 deletions
@@ -67,6 +67,7 @@ public interface BindingContext {
WritableSlice<JetTypeReference, JetType> TYPE = Slices.createSimpleSlice();
WritableSlice<JetExpression, JetType> EXPRESSION_TYPE = new BasicWritableSlice<JetExpression, JetType>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice<JetExpression, DataFlowInfo>(DO_NOTHING);
WritableSlice<JetExpression, DataFlowInfo> DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice();
WritableSlice<JetReferenceExpression, DeclarationDescriptor> REFERENCE_TARGET =
new BasicWritableSlice<JetReferenceExpression, DeclarationDescriptor>(DO_NOTHING);
@@ -20,7 +20,6 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
@@ -35,8 +34,6 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
@@ -55,16 +52,7 @@ public class DataFlowUtils {
@Override
public void visitIsExpression(JetIsExpression expression) {
if (conditionValue && !expression.isNegated() || !conditionValue && expression.isNegated()) {
JetPattern pattern = expression.getPattern();
result.set(context.patternsToDataFlowInfo.get(pattern));
if (scopeToExtend != null) {
List<VariableDescriptor> descriptors = context.patternsToBoundVariableLists.get(pattern);
if (descriptors != null) {
for (VariableDescriptor variableDescriptor : descriptors) {
scopeToExtend.addVariableDescriptor(variableDescriptor);
}
}
}
result.set(context.trace.get(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression));
}
}
@@ -21,7 +21,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.BasicResolutionContext;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
@@ -34,9 +36,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
@@ -51,22 +51,19 @@ public class ExpressionTypingContext {
@NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType expectedType,
boolean namespacesAllowed) {
return newContext(expressionTypingServices, new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(),
new LabelResolver(), trace, scope, dataFlowInfo, expectedType, namespacesAllowed);
return newContext(expressionTypingServices, new LabelResolver(), trace, scope, dataFlowInfo, expectedType, namespacesAllowed);
}
@NotNull
public static ExpressionTypingContext newContext(
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo,
@NotNull Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists,
@NotNull LabelResolver labelResolver,
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType expectedType,
boolean namespacesAllowed) {
return new ExpressionTypingContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists,
return new ExpressionTypingContext(expressionTypingServices,
labelResolver, trace, scope, dataFlowInfo, expectedType, namespacesAllowed);
}
@@ -77,8 +74,6 @@ public class ExpressionTypingContext {
public final DataFlowInfo dataFlowInfo;
public final JetType expectedType;
public final Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo;
public final Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists;
public final LabelResolver labelResolver;
// true for positions on the lhs of a '.', i.e. allows namespace results and 'super'
@@ -88,8 +83,6 @@ public class ExpressionTypingContext {
private ExpressionTypingContext(
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo,
@NotNull Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists,
@NotNull LabelResolver labelResolver,
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@@ -98,8 +91,6 @@ public class ExpressionTypingContext {
boolean namespacesAllowed) {
this.expressionTypingServices = expressionTypingServices;
this.trace = trace;
this.patternsToBoundVariableLists = patternsToBoundVariableLists;
this.patternsToDataFlowInfo = patternsToDataFlowInfo;
this.labelResolver = labelResolver;
this.scope = scope;
this.dataFlowInfo = dataFlowInfo;
@@ -110,14 +101,14 @@ public class ExpressionTypingContext {
@NotNull
public ExpressionTypingContext replaceNamespacesAllowed(boolean namespacesAllowed) {
if (namespacesAllowed == this.namespacesAllowed) return this;
return newContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver,
return newContext(expressionTypingServices, labelResolver,
trace, scope, dataFlowInfo, expectedType, namespacesAllowed);
}
@NotNull
public ExpressionTypingContext replaceDataFlowInfo(DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return this;
return newContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver,
return newContext(expressionTypingServices, labelResolver,
trace, scope, newDataFlowInfo, expectedType, namespacesAllowed);
}
@@ -125,21 +116,21 @@ public class ExpressionTypingContext {
public ExpressionTypingContext replaceExpectedType(@Nullable JetType newExpectedType) {
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return this;
return newContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver,
return newContext(expressionTypingServices, labelResolver,
trace, scope, dataFlowInfo, newExpectedType, namespacesAllowed);
}
@NotNull
public ExpressionTypingContext replaceBindingTrace(@NotNull BindingTrace newTrace) {
if (newTrace == trace) return this;
return newContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver,
return newContext(expressionTypingServices, labelResolver,
newTrace, scope, dataFlowInfo, expectedType, namespacesAllowed);
}
@NotNull
public ExpressionTypingContext replaceScope(@NotNull JetScope newScope) {
if (newScope == scope) return this;
return newContext(expressionTypingServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver,
return newContext(expressionTypingServices, labelResolver,
trace, newScope, dataFlowInfo, expectedType, namespacesAllowed);
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -356,8 +355,7 @@ public class ExpressionTypingServices {
private ExpressionTypingContext createContext(ExpressionTypingContext oldContext, BindingTrace trace, WritableScope scope, DataFlowInfo dataFlowInfo, JetType expectedType) {
return ExpressionTypingContext.newContext(
this, oldContext.patternsToDataFlowInfo, oldContext.patternsToBoundVariableLists, oldContext.labelResolver,
trace, scope, dataFlowInfo, expectedType, oldContext.namespacesAllowed);
this, oldContext.labelResolver, trace, scope, dataFlowInfo, expectedType, oldContext.namespacesAllowed);
}
private ObservableBindingTrace makeTraceInterceptingTypeMismatch(final BindingTrace trace, final JetExpression expressionToWatch, final boolean[] mismatchFound) {
@@ -17,28 +17,22 @@
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;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
@@ -57,14 +51,11 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
JetExpression leftHandSide = expression.getLeftHandSide();
JetType knownType = facade.safeGetTypeInfo(leftHandSide, context.replaceScope(context.scope)).getType();
JetPattern pattern = expression.getPattern();
DataFlowInfo newDataFlowInfo = context.dataFlowInfo;
if (pattern != null) {
WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in 'is'");
if (expression.getTypeRef() != null) {
DataFlowValue dataFlowValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(leftHandSide, knownType, context.trace.getBindingContext());
newDataFlowInfo = checkPatternType(pattern, knownType, false, scopeToExtend, context, dataFlowValue).first;
context.patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
context.patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
newDataFlowInfo = checkTypeForIs(context, knownType, expression.getTypeRef(), dataFlowValue).thenInfo;
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo);
}
return DataFlowUtils.checkType(JetStandardLibrary.getInstance().getBooleanType(), expression, contextWithExpectedType, newDataFlowInfo);
}
@@ -102,23 +93,27 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
newDataFlowInfo = context.dataFlowInfo;
JetWhenCondition condition = conditions[0];
if (condition != null) {
Pair<DataFlowInfo, DataFlowInfo> infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, scopeToExtend, context, variableDescriptor);
newDataFlowInfo = infos.first;
elseDataFlowInfo = elseDataFlowInfo.and(infos.second);
DataFlowInfos infos = checkWhenCondition(
subjectExpression, subjectExpression == null,
subjectType, condition,
context, variableDescriptor);
newDataFlowInfo = infos.thenInfo;
elseDataFlowInfo = elseDataFlowInfo.and(infos.elseInfo);
}
}
else {
scopeToExtend = newWritableScopeImpl(context, "pattern matching"); // We don't write to this scope
newDataFlowInfo = null;
for (JetWhenCondition condition : conditions) {
Pair<DataFlowInfo, DataFlowInfo> infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition, newWritableScopeImpl(context, ""), context, variableDescriptor);
DataFlowInfos infos = checkWhenCondition(subjectExpression, subjectExpression == null, subjectType, condition,
context, variableDescriptor);
if (newDataFlowInfo == null) {
newDataFlowInfo = infos.first;
newDataFlowInfo = infos.thenInfo;
}
else {
newDataFlowInfo = newDataFlowInfo.or(infos.first);
newDataFlowInfo = newDataFlowInfo.or(infos.thenInfo);
}
elseDataFlowInfo = elseDataFlowInfo.and(infos.second);
elseDataFlowInfo = elseDataFlowInfo.and(infos.elseInfo);
}
if (newDataFlowInfo == null) {
newDataFlowInfo = context.dataFlowInfo;
@@ -152,8 +147,15 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return JetTypeInfo.create(null, commonDataFlowInfo);
}
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));
private DataFlowInfos checkWhenCondition(
@Nullable final JetExpression subjectExpression,
final boolean expectedCondition,
final JetType subjectType,
JetWhenCondition condition,
final ExpressionTypingContext context,
final DataFlowValue... subjectVariables
) {
final Ref<DataFlowInfos> newDataFlowInfo = new Ref<DataFlowInfos>(noChange(context));
condition.accept(new JetVisitorVoid() {
@Override
@@ -172,14 +174,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
@Override
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
JetPattern pattern = condition.getPattern();
if (expectedCondition) {
context.trace.report(EXPECTED_CONDITION.on(condition));
}
if (pattern != null) {
Pair<DataFlowInfo, DataFlowInfo> result = checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables);
if (condition.getTypeRef() != null) {
DataFlowInfos result = checkTypeForIs(context, subjectType, condition.getTypeRef(), subjectVariables);
if (condition.isNegated()) {
newDataFlowInfo.set(Pair.create(result.second, result.first));
newDataFlowInfo.set(new DataFlowInfos(result.elseInfo, result.thenInfo));
}
else {
newDataFlowInfo.set(result);
@@ -189,9 +190,10 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
@Override
public void visitWhenConditionWithExpression(JetWhenConditionWithExpression condition) {
JetPattern pattern = condition.getPattern();
if (pattern != null) {
newDataFlowInfo.set(checkPatternType(pattern, subjectType, subjectExpression == null, scopeToExtend, context, subjectVariables));
JetExpression expression = condition.getExpression();
if (expression != null) {
newDataFlowInfo.set(checkTypeForExpressionCondition(context, expression, subjectType, subjectExpression == null,
subjectVariables));
}
}
@@ -203,148 +205,98 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return newDataFlowInfo.get();
}
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<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) {
JetTypeReference typeReference = typePattern.getTypeReference();
if (typeReference == null) return;
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReference, context.trace, true);
checkTypeCompatibility(type, subjectType, typePattern);
if (BasicExpressionTypingVisitor.isCastErased(subjectType, type, JetTypeChecker.INSTANCE)) {
context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReference, type));
}
result.set(Pair.create(context.dataFlowInfo.establishSubtyping(subjectVariables, type), context.dataFlowInfo));
}
private static class DataFlowInfos {
private final DataFlowInfo thenInfo;
private final DataFlowInfo elseInfo;
@Override
public void visitTuplePattern(JetTuplePattern pattern) {
List<JetTuplePatternEntry> entries = pattern.getEntries();
TypeConstructor typeConstructor = subjectType.getConstructor();
if (!JetStandardClasses.getTuple(entries.size()).getTypeConstructor().equals(typeConstructor)
|| typeConstructor.getParameters().size() != entries.size()) {
context.trace.report(TYPE_MISMATCH_IN_TUPLE_PATTERN.on(pattern, subjectType, entries.size()));
return;
}
for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {
JetTuplePatternEntry entry = entries.get(i);
JetType type = subjectType.getArguments().get(i).getType();
// TODO : is a name always allowed, ie for tuple patterns, not decomposer arg lists?
ASTNode nameLabelNode = entry.getNameLabelNode();
if (nameLabelNode != null) {
// context.trace.getErrorHandler().genericError(nameLabelNode, "Unsupported [OperatorConventions]");
context.trace.report(UNSUPPORTED.on(nameLabelNode.getPsi(), getClass().getCanonicalName()));
}
JetPattern entryPattern = entry.getPattern();
if (entryPattern != null) {
Pair<DataFlowInfo, DataFlowInfo> dataFlowInfos = checkPatternType(entryPattern, type, false, scopeToExtend, context);
result.set(Pair.create(result.get().first.and(dataFlowInfos.first), context.dataFlowInfo));
}
}
}
@Override
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
JetExpression decomposerExpression = pattern.getDecomposerExpression();
if (decomposerExpression != null) {
ReceiverDescriptor receiver = new TransientReceiver(subjectType);
JetType selectorReturnType = facade.getSelectorReturnTypeInfo(receiver, null, decomposerExpression, context).getType();
if (pattern.getArgumentList() != null) {
result.set(checkPatternType(pattern.getArgumentList(), selectorReturnType == null
? ErrorUtils.createErrorType("No type")
: selectorReturnType, false, scopeToExtend, context));
}
}
}
@Override
public void visitWildcardPattern(JetWildcardPattern pattern) {
// Nothing
}
@Override
public void visitExpressionPattern(JetExpressionPattern pattern) {
JetExpression expression = pattern.getExpression();
if (expression == null) return;
JetTypeInfo typeInfo = facade.getTypeInfo(expression, context.replaceScope(scopeToExtend));
JetType type = typeInfo.getType();
if (type == null) return;
if (conditionExpected) {
JetType booleanType = JetStandardLibrary.getInstance().getBooleanType();
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
public void visitBindingPattern(JetBindingPattern pattern) {
JetProperty variableDeclaration = pattern.getVariableDeclaration();
JetTypeReference propertyTypeRef = variableDeclaration.getTypeRef();
JetType type = propertyTypeRef == null ? subjectType : context.expressionTypingServices.getTypeResolver().resolveType(context.scope, propertyTypeRef, context.trace, true);
VariableDescriptor variableDescriptor = context.expressionTypingServices.getDescriptorResolver().resolveLocalVariableDescriptorWithType(context.scope.getContainingDeclaration(), variableDeclaration, type, context.trace);
scopeToExtend.addVariableDescriptor(variableDescriptor);
if (propertyTypeRef != null) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(subjectType, type)) {
context.trace.report(TYPE_MISMATCH_IN_BINDING_PATTERN.on(propertyTypeRef, type, subjectType));
}
}
JetWhenCondition condition = pattern.getCondition();
if (condition != null) {
int oldLength = subjectVariables.length;
DataFlowValue[] newSubjectVariables = new DataFlowValue[oldLength + 1];
System.arraycopy(subjectVariables, 0, newSubjectVariables, 0, oldLength);
newSubjectVariables[oldLength] = DataFlowValueFactory.INSTANCE.createDataFlowValue(variableDescriptor);
result.set(checkWhenCondition(null, false, subjectType, condition, scopeToExtend, context, newSubjectVariables));
}
}
/*
* (a: SubjectType) is Type
*/
private void checkTypeCompatibility(@Nullable JetType type, @NotNull JetType subjectType, @NotNull JetElement reportErrorOn) {
// TODO : Take auto casts into account?
if (type == null) {
return;
}
if (TypeUtils.isIntersectionEmpty(type, subjectType)) {
context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType));
return;
}
// check if the pattern is essentially a 'null' expression
if (type == JetStandardClasses.getNullableNothingType() && !subjectType.isNullable()) {
context.trace.report(SENSELESS_NULL_IN_WHEN.on(reportErrorOn));
}
}
@Override
public void visitJetElement(JetElement element) {
context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName()));
}
});
return result.get();
private DataFlowInfos(DataFlowInfo thenInfo, DataFlowInfo elseInfo) {
this.thenInfo = thenInfo;
this.elseInfo = elseInfo;
}
}
private DataFlowInfos checkTypeForExpressionCondition(
ExpressionTypingContext context,
JetExpression expression,
JetType subjectType,
boolean conditionExpected,
DataFlowValue... subjectVariables
) {
if (expression == null) {
return noChange(context);
}
JetTypeInfo typeInfo = facade.getTypeInfo(expression, context);
JetType type = typeInfo.getType();
if (type == null) {
return noChange(context);
}
if (conditionExpected) {
JetType booleanType = JetStandardLibrary.getInstance().getBooleanType();
if (!JetTypeChecker.INSTANCE.equalTypes(booleanType, type)) {
context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type));
}
else {
DataFlowInfo ifInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, true, null, context);
DataFlowInfo elseInfo = DataFlowUtils.extractDataFlowInfoFromCondition(expression, false, null, context);
return new DataFlowInfos(ifInfo, elseInfo);
}
return noChange(context);
}
checkTypeCompatibility(context, type, subjectType, expression);
DataFlowValue expressionDataFlowValue =
DataFlowValueFactory.INSTANCE.createDataFlowValue(expression, type, context.trace.getBindingContext());
DataFlowInfos result = noChange(context);
for (DataFlowValue subjectVariable : subjectVariables) {
result = new DataFlowInfos(
result.thenInfo.equate(subjectVariable, expressionDataFlowValue),
result.elseInfo.disequate(subjectVariable, expressionDataFlowValue)
);
}
return result;
}
private static DataFlowInfos checkTypeForIs(
ExpressionTypingContext context,
JetType subjectType,
JetTypeReference typeReferenceAfterIs,
DataFlowValue... subjectVariables
) {
if (typeReferenceAfterIs == null) {
return noChange(context);
}
JetType type = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, typeReferenceAfterIs, context.trace, true);
checkTypeCompatibility(context, type, subjectType, typeReferenceAfterIs);
if (BasicExpressionTypingVisitor.isCastErased(subjectType, type, JetTypeChecker.INSTANCE)) {
context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, type));
}
return new DataFlowInfos(context.dataFlowInfo.establishSubtyping(subjectVariables, type), context.dataFlowInfo);
}
private static DataFlowInfos noChange(ExpressionTypingContext context) {
return new DataFlowInfos(context.dataFlowInfo, context.dataFlowInfo);
}
/*
* (a: SubjectType) is Type
*/
private static void checkTypeCompatibility(
@NotNull ExpressionTypingContext context,
@Nullable JetType type,
@NotNull JetType subjectType,
@NotNull JetElement reportErrorOn
) {
// TODO : Take auto casts into account?
if (type == null) {
return;
}
if (TypeUtils.isIntersectionEmpty(type, subjectType)) {
context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType));
return;
}
// check if the pattern is essentially a 'null' expression
if (type == JetStandardClasses.getNullableNothingType() && !subjectType.isNullable()) {
context.trace.report(SENSELESS_NULL_IN_WHEN.on(reportErrorOn));
}
}
}