private ValueDispatchNode GatherValueDispatchNodes(
                BoundDecisionDagNode node,
                HashSet <BoundDecisionDagNode> loweredNodes,
                BoundDagTemp input,
                IValueSetFactory fac)
            {
                if (loweredNodes.Contains(node))
                {
                    bool foundLabel = this._dagNodeLabels.TryGetValue(node, out LabelSymbol label);
                    Debug.Assert(foundLabel);
                    return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label));
                }
                if (!(node is BoundTestDecisionDagNode testNode && testNode.Test.Input.Equals(input)))
                {
                    var label = GetDagNodeLabel(node);
                    return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label));
                }

                switch (testNode.Test)
                {
                case BoundDagRelationalTest relational:
                {
                    loweredNodes.Add(testNode);
                    var whenTrue  = GatherValueDispatchNodes(testNode.WhenTrue, loweredNodes, input, fac);
                    var whenFalse = GatherValueDispatchNodes(testNode.WhenFalse, loweredNodes, input, fac);
                    return(ValueDispatchNode.RelationalDispatch.CreateBalanced(testNode.Syntax, relational.Value, relational.OperatorKind, whenTrue: whenTrue, whenFalse: whenFalse));
                }

                case BoundDagValueTest value:
                {
                    // Gather up the (value, label) pairs, starting with the first one
                    loweredNodes.Add(testNode);
                    var cases = ArrayBuilder <(ConstantValue value, LabelSymbol label)> .GetInstance();

                    cases.Add((value: value.Value, label: GetDagNodeLabel(testNode.WhenTrue)));
                    BoundTestDecisionDagNode previous = testNode;
                    while (previous.WhenFalse is BoundTestDecisionDagNode p &&
                           p.Test is BoundDagValueTest vd &&
                           vd.Input.Equals(input) &&
                           !this._dagNodeLabels.ContainsKey(p) &&
                           !loweredNodes.Contains(p))
                    {
                        cases.Add((value: vd.Value, label: GetDagNodeLabel(p.WhenTrue)));
                        loweredNodes.Add(p);
                        previous = p;
                    }

                    var otherwise = GatherValueDispatchNodes(previous.WhenFalse, loweredNodes, input, fac);
                    return(PushEqualityTestsIntoTree(value.Syntax, otherwise, cases.ToImmutableAndFree(), fac));
                }

                default:
                {
                    var label = GetDagNodeLabel(node);
                    return(new ValueDispatchNode.LeafDispatchNode(node.Syntax, label));
                }
                }
            }
            private bool GenerateSwitchDispatch(BoundDecisionDagNode node, HashSet <BoundDecisionDagNode> loweredNodes)
            {
                Debug.Assert(!loweredNodes.Contains(node));

                // We only generate a switch dispatch if we have two or more value tests in a row
                if (!(node is BoundTestDecisionDagNode firstTestNode &&
                      firstTestNode.Test is BoundDagValueTest firstTest &&
                      firstTestNode.WhenFalse is BoundTestDecisionDagNode whenFalse &&
                      whenFalse.Test is BoundDagValueTest secondTest &&
                      !loweredNodes.Contains(whenFalse) &&
                      !this._dagNodeLabels.ContainsKey(whenFalse) &&
                      firstTest.Input == secondTest.Input &&
                      firstTest.Input.Type.IsValidV6SwitchGoverningType()))
                {
                    // https://github.com/dotnet/roslyn/issues/12509 Could optimize float, double, decimal value switches. For now use if-then-else
                    return(false);
                }

                // Gather up the (value, label) pairs, starting with the first one
                var cases = ArrayBuilder <(ConstantValue value, LabelSymbol label)> .GetInstance();

                cases.Add((value: firstTest.Value, label: GetDagNodeLabel(firstTestNode.WhenTrue)));

                BoundTestDecisionDagNode previous = firstTestNode;

                while (previous.WhenFalse is BoundTestDecisionDagNode p &&
                       p.Test is BoundDagValueTest vd &&
                       vd.Input == firstTest.Input &&
                       !this._dagNodeLabels.ContainsKey(p) &&
                       !loweredNodes.Contains(p))
                {
                    cases.Add((value: vd.Value, label: GetDagNodeLabel(p.WhenTrue)));
                    loweredNodes.Add(p);
                    previous = p;
                }

                // If we are emitting a hash table based string switch,
                // we need to generate a helper method for computing
                // string hash value in <PrivateImplementationDetails> class.

                MethodSymbol?stringEquality = null;

                if (firstTest.Input.Type.SpecialType == SpecialType.System_String)
                {
                    EnsureStringHashFunction(cases.Count, node.Syntax);
                    stringEquality = _localRewriter.UnsafeGetSpecialTypeMethod(node.Syntax, SpecialMember.System_String__op_Equality);
                }

                LabelSymbol defaultLabel = GetDagNodeLabel(previous.WhenFalse);
                var         dispatch     = new BoundSwitchDispatch(
                    node.Syntax, _tempAllocator.GetTemp(firstTest.Input), cases.ToImmutableAndFree(), defaultLabel, stringEquality);

                _loweredDecisionDag.Add(dispatch);
                return(true);
            }