/// <summary>
        /// Learn from any constant null patterns appearing in the pattern.
        /// </summary>
        /// <param name="inputType">Type type of the input expression (before nullable analysis).
        /// Used to determine which types can contain null.</param>
        /// <returns>true if there is a top-level explicit null check</returns>
        private void LearnFromAnyNullPatterns(
            int inputSlot,
            TypeSymbol inputType,
            BoundPattern pattern)
        {
            if (inputSlot <= 0)
            {
                return;
            }

            switch (pattern)
            {
            case BoundConstantPattern cp:
                bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null;
                if (isExplicitNullCheck)
                {
                    LearnFromNullTest(inputSlot, inputType, ref this.State);
                }
                break;

            case BoundDeclarationPattern _:
            case BoundDiscardPattern _:
            case BoundITuplePattern _:
                break;     // nothing to learn

            case BoundRecursivePattern rp:
            {
                // for positional part: we only learn from tuples (not Deconstruct)
                if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault)
                {
                    var elements = inputType.TupleElements;
                    for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++)
                    {
                        BoundSubpattern item    = rp.Deconstruction[i];
                        FieldSymbol     element = elements[i];
                        LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern);
                    }
                }

                // for property part
                if (!rp.Properties.IsDefault)
                {
                    for (int i = 0, n = rp.Properties.Length; i < n; i++)
                    {
                        BoundSubpattern item   = rp.Properties[i];
                        Symbol          symbol = item.Symbol;
                        if (symbol?.ContainingType.Equals(inputType, TypeCompareKind.AllIgnoreOptions) == true)
                        {
                            LearnFromAnyNullPatterns(GetOrCreateSlot(symbol, inputSlot), symbol.GetTypeOrReturnType().Type, item.Pattern);
                        }
                    }
                }
            }
            break;

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern);
            }
        }
 public override BoundNode VisitSubpattern(BoundSubpattern node)
 {
     Visit(node.Pattern);
     return(null);
 }
        /// <summary>
        /// Learn from any constant null patterns appearing in the pattern.
        /// </summary>
        /// <param name="inputType">Type type of the input expression (before nullable analysis).
        /// Used to determine which types can contain null.</param>
        private void LearnFromAnyNullPatterns(
            int inputSlot,
            TypeSymbol inputType,
            BoundPattern pattern)
        {
            if (inputSlot <= 0)
            {
                return;
            }

            // https://github.com/dotnet/roslyn/issues/35041 We only need to do this when we're rewriting, so we
            // can get information for any nodes in the pattern.
            VisitPatternForRewriting(pattern);

            switch (pattern)
            {
            case BoundConstantPattern cp:
                bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null;
                if (isExplicitNullCheck)
                {
                    // Since we're not branching on this null test here, we just infer the top level
                    // nullability.  We'll branch on it later.
                    LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false);
                }
                break;

            case BoundDeclarationPattern _:
            case BoundDiscardPattern _:
            case BoundITuplePattern _:
                break;     // nothing to learn

            case BoundRecursivePattern rp:
            {
                if (rp.IsExplicitNotNullTest)
                {
                    LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false);
                }

                // for positional part: we only learn from tuples (not Deconstruct)
                if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault)
                {
                    var elements = inputType.TupleElements;
                    for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++)
                    {
                        BoundSubpattern item    = rp.Deconstruction[i];
                        FieldSymbol     element = elements[i];
                        LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern);
                    }
                }

                // for property part
                if (!rp.Properties.IsDefault)
                {
                    for (int i = 0, n = rp.Properties.Length; i < n; i++)
                    {
                        BoundSubpattern item   = rp.Properties[i];
                        Symbol          symbol = item.Symbol;
                        if (symbol?.ContainingType.Equals(inputType, TypeCompareKind.AllIgnoreOptions) == true)
                        {
                            LearnFromAnyNullPatterns(GetOrCreateSlot(symbol, inputSlot), symbol.GetTypeOrReturnType().Type, item.Pattern);
                        }
                    }
                }
            }
            break;

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern);
            }
        }
        private void LearnFromAnyNullPatterns(
            int inputSlot,
            TypeSymbol inputType,
            BoundPattern pattern)
        {
            if (inputSlot <= 0)
            {
                return;
            }

            // https://github.com/dotnet/roslyn/issues/35041 We only need to do this when we're rewriting, so we
            // can get information for any nodes in the pattern.
            VisitPatternForRewriting(pattern);

            switch (pattern)
            {
            case BoundConstantPattern cp:
                bool isExplicitNullCheck = cp.Value.ConstantValue == ConstantValue.Null;
                if (isExplicitNullCheck)
                {
                    // Since we're not branching on this null test here, we just infer the top level
                    // nullability.  We'll branch on it later.
                    LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false);
                }
                break;

            case BoundDeclarationPattern _:
            case BoundDiscardPattern _:
            case BoundITuplePattern _:
            case BoundRelationalPattern _:
                break;     // nothing to learn

            case BoundTypePattern tp:
                if (tp.IsExplicitNotNullTest)
                {
                    LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false);
                }
                break;

            case BoundRecursivePattern rp:
            {
                if (rp.IsExplicitNotNullTest)
                {
                    LearnFromNullTest(inputSlot, inputType, ref this.State, markDependentSlotsNotNull: false);
                }

                // for positional part: we only learn from tuples (not Deconstruct)
                if (rp.DeconstructMethod is null && !rp.Deconstruction.IsDefault)
                {
                    var elements = inputType.TupleElements;
                    for (int i = 0, n = Math.Min(rp.Deconstruction.Length, elements.IsDefault ? 0 : elements.Length); i < n; i++)
                    {
                        BoundSubpattern item    = rp.Deconstruction[i];
                        FieldSymbol     element = elements[i];
                        LearnFromAnyNullPatterns(GetOrCreateSlot(element, inputSlot), element.Type, item.Pattern);
                    }
                }

                // for property part
                if (!rp.Properties.IsDefault)
                {
                    foreach (BoundPropertySubpattern subpattern in rp.Properties)
                    {
                        if (subpattern.Member is BoundPropertySubpatternMember member)
                        {
                            LearnFromAnyNullPatterns(getExtendedPropertySlot(member, inputSlot), member.Type, subpattern.Pattern);
                        }
                    }
                }
            }
            break;

            case BoundNegatedPattern p:
                LearnFromAnyNullPatterns(inputSlot, inputType, p.Negated);
                break;

            case BoundBinaryPattern p:
                LearnFromAnyNullPatterns(inputSlot, inputType, p.Left);
                LearnFromAnyNullPatterns(inputSlot, inputType, p.Right);
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(pattern);
            }

            int getExtendedPropertySlot(BoundPropertySubpatternMember member, int inputSlot)
            {
                if (member.Symbol is null)
                {
                    return(-1);
                }

                if (member.Receiver is not null)
                {
                    inputSlot = getExtendedPropertySlot(member.Receiver, inputSlot);
                }

                if (inputSlot < 0)
                {
                    return(inputSlot);
                }

                return(GetOrCreateSlot(member.Symbol, inputSlot));
            }
        }