LearnFromDecisionDag( SyntaxNode node, BoundDecisionDag decisionDag, BoundExpression expression, TypeWithState expressionType, ref PossiblyConditionalState initialState) { // We reuse the slot at the beginning of a switch (or is-pattern expression), pretending that we are // not copying the input to evaluate the patterns. In this way we infer non-nullability of the original // variable's parts based on matched pattern parts. Mutations in `when` clauses can show the inaccuracy // of analysis based on this choice. var rootTemp = BoundDagTemp.ForOriginalInput(expression); int originalInputSlot = MakeSlot(expression); if (originalInputSlot <= 0) { originalInputSlot = makeDagTempSlot(expressionType.ToTypeWithAnnotations(compilation), rootTemp); } Debug.Assert(originalInputSlot > 0); // If the input of the switch (or is-pattern expression) is a tuple literal, we reuse the slots of // those expressions (when possible), pretending that we are not copying them into a temporary ValueTuple instance // to evaluate the patterns. In this way we infer non-nullability of the original element's parts. // We do not extend such courtesy to nested tuple literals. var originalInputElementSlots = expression is BoundTupleExpression tuple ? tuple.Arguments.SelectAsArray(static (a, w) => w.MakeSlot(a), this)
protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement node) { // first, learn from any null tests in the patterns int slot = node.Expression.IsSuppressed ? GetOrCreatePlaceholderSlot(node.Expression) : MakeSlot(node.Expression); if (slot > 0) { var originalInputType = node.Expression.Type; foreach (var section in node.SwitchSections) { foreach (var label in section.SwitchLabels) { LearnFromAnyNullPatterns(slot, originalInputType, label.Pattern); } } } // visit switch header Visit(node.Expression); var expressionState = ResultType; var initialState = PossiblyConditionalState.Create(this); DeclareLocals(node.InnerLocals); foreach (var section in node.SwitchSections) { // locals can be alive across jumps in the switch sections, so we declare them early. DeclareLocals(section.Locals); } var labelStateMap = LearnFromDecisionDag(node.Syntax, node.DecisionDag, node.Expression, expressionState, ref initialState); foreach (var section in node.SwitchSections) { foreach (var label in section.SwitchLabels) { var labelResult = labelStateMap.TryGetValue(label.Label, out var s1) ? s1 : (state : UnreachableState(), believedReachable : false); SetState(labelResult.state); PendingBranches.Add(new PendingBranch(label, this.State, label.Label)); } } var afterSwitchState = labelStateMap.TryGetValue(node.BreakLabel, out var stateAndReachable) ? stateAndReachable.state : UnreachableState(); labelStateMap.Free(); return(afterSwitchState); }