private static IList <CSharpSwitchCase> ReduceGotos(IList <CSharpSwitchCase> cases)
        {
            var testValueToCaseMap = new Dictionary <object, CSharpSwitchCase>();

            var analyzer = new SwitchCaseGotoAnalyzer();

            var defaultCase = default(CSharpSwitchCase);

            foreach (var @case in cases)
            {
                foreach (var testValue in @case.TestValues)
                {
                    if (testValue == SwitchCaseDefaultValue)
                    {
                        defaultCase = @case;
                    }

                    testValueToCaseMap.Add(testValue.OrNullSentinel(), @case);
                }

                analyzer.Analyze(@case);
            }

            var caseHasJumpInto = new HashSet <CSharpSwitchCase>();

            foreach (var info in analyzer.SwitchCaseInfos.Values)
            {
                if (info.HasGotoDefault)
                {
                    if (defaultCase == null)
                    {
                        throw Error.InvalidGotoDefault();
                    }

                    caseHasJumpInto.Add(defaultCase);
                }

                foreach (var gotoCase in info.GotoCases)
                {
                    if (!testValueToCaseMap.TryGetValue(gotoCase.OrNullSentinel(), out CSharpSwitchCase @case))
                    {
                        throw Error.InvalidGotoCase(gotoCase.ToDebugString());
                    }

                    caseHasJumpInto.Add(@case);
                }
            }

            if (caseHasJumpInto.Count > 0)
            {
                var caseJumpTargets   = new Dictionary <CSharpSwitchCase, LabelTarget>();
                var defaultJumpTarget = default(LabelTarget);

                foreach (var @case in caseHasJumpInto)
                {
                    var label = default(LabelTarget);

                    if (@case == defaultCase)
                    {
                        label = defaultJumpTarget = Expression.Label("__default");
                    }
                    else
                    {
                        label = Expression.Label(FormattableString.Invariant($"__case<{@case.TestValues[0].ToDebugString()}>"));
                    }

                    caseJumpTargets.Add(@case, label);
                }

                var rewriter = new SwitchCaseRewriter(testValue => caseJumpTargets[testValueToCaseMap[testValue.OrNullSentinel()]], defaultJumpTarget);

                var newCases = new CSharpSwitchCase[cases.Count];

                var i = 0;
                foreach (var @case in cases)
                {
                    var newBody = rewriter.Visit(@case.Statements);

                    if (caseJumpTargets.TryGetValue(@case, out LabelTarget jumpTarget))
                    {
                        newBody = newBody.AddFirst(Expression.Label(jumpTarget)).ToReadOnly();
                    }

                    newCases[i++] = @case.Update(newBody);
                }

                return(newCases);
            }
            else
            {
                return(cases);
            }
        }
        private static IList<CSharpSwitchCase> ReduceGotos(IList<CSharpSwitchCase> cases)
        {
            var testValueToCaseMap = new Dictionary<object, CSharpSwitchCase>();

            var analyzer = new SwitchCaseGotoAnalyzer();

            var defaultCase = default(CSharpSwitchCase);

            foreach (var @case in cases)
            {
                foreach (var testValue in @case.TestValues)
                {
                    if (testValue == SwitchCaseDefaultValue)
                    {
                        defaultCase = @case;
                    }

                    testValueToCaseMap.Add(testValue.OrNullSentinel(), @case);
                }

                analyzer.Analyze(@case);
            }

            var caseHasJumpInto = new HashSet<CSharpSwitchCase>();

            foreach (var info in analyzer.SwitchCaseInfos.Values)
            {
                if (info.HasGotoDefault)
                {
                    if (defaultCase == null)
                    {
                        throw Error.InvalidGotoDefault();
                    }

                    caseHasJumpInto.Add(defaultCase);
                }

                foreach (var gotoCase in info.GotoCases)
                {
                    var @case = default(CSharpSwitchCase);
                    if (!testValueToCaseMap.TryGetValue(gotoCase.OrNullSentinel(), out @case))
                    {
                        throw Error.InvalidGotoCase(gotoCase.ToDebugString());
                    }

                    caseHasJumpInto.Add(@case);
                }
            }

            if (caseHasJumpInto.Count > 0)
            {
                var caseJumpTargets = new Dictionary<CSharpSwitchCase, LabelTarget>();
                var defaultJumpTarget = default(LabelTarget);

                foreach (var @case in caseHasJumpInto)
                {
                    var label = default(LabelTarget);

                    if (@case == defaultCase)
                    {
                        label = defaultJumpTarget = Expression.Label("__default");
                    }
                    else
                    {
                        label = Expression.Label(FormattableString.Invariant($"__case<{@case.TestValues[0].ToDebugString()}>"));
                    }

                    caseJumpTargets.Add(@case, label);
                }

                var rewriter = new SwitchCaseRewriter(testValue => caseJumpTargets[testValueToCaseMap[testValue.OrNullSentinel()]], defaultJumpTarget);

                var newCases = new CSharpSwitchCase[cases.Count];

                var i = 0;
                foreach (var @case in cases)
                {
                    var newBody = rewriter.Visit(@case.Statements);

                    var jumpTarget = default(LabelTarget);
                    if (caseJumpTargets.TryGetValue(@case, out jumpTarget))
                    {
                        newBody = newBody.AddFirst(Expression.Label(jumpTarget)).ToReadOnly();
                    }

                    newCases[i++] = @case.Update(newBody);
                }

                return newCases;
            }
            else
            {
                return cases;
            }
        }