From 756ca9b28409e0fc09d545f35c504236a3556584 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 5 Sep 2012 12:52:31 +0400 Subject: [PATCH] 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 patternsToDataFlowInfo in ExpressionTypingContext, we fall back for a slice in the trace. Refactoring: DataFlowInfos class introduced to repace a Pair #KT-2359 In Progress --- .../jet/lang/resolve/BindingContext.java | 1 + .../lang/types/expressions/DataFlowUtils.java | 14 +- .../expressions/ExpressionTypingContext.java | 29 +- .../expressions/ExpressionTypingServices.java | 4 +- .../PatternMatchingTypingVisitor.java | 292 ++++++++---------- 5 files changed, 135 insertions(+), 205 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index e902bccbd86..549d3b485c0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -67,6 +67,7 @@ public interface BindingContext { WritableSlice TYPE = Slices.createSimpleSlice(); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice(DO_NOTHING); + WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); WritableSlice REFERENCE_TARGET = new BasicWritableSlice(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index a4718c4fa38..2eca636263b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -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 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)); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java index 824088e5e28..dc364698790 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingContext.java @@ -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(), new HashMap>(), - 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 patternsToDataFlowInfo, - @NotNull Map> 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 patternsToDataFlowInfo; - public final Map> 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 patternsToDataFlowInfo, - @NotNull Map> 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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index fc18978a452..aa5f2b19ff6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -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) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index e4ffb77ef42..c13a044ee90 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -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 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 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 checkWhenCondition(@Nullable final JetExpression subjectExpression, final boolean expectedCondition, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final ExpressionTypingContext context, final DataFlowValue... subjectVariables) { - final Ref> newDataFlowInfo = new Ref>(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 newDataFlowInfo = new Ref(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 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 checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, final boolean conditionExpected, - @NotNull final WritableScope scopeToExtend, final ExpressionTypingContext context, @NotNull final DataFlowValue... subjectVariables - ) { - final Ref> result = new Ref>(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 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 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)); + } + } }