private BoundExpression LowerSwitchExpression(BoundSwitchExpression node)
            {
                _factory.Syntax = node.Syntax;
                var result = ArrayBuilder <BoundStatement> .GetInstance();

                var outerVariables = ArrayBuilder <LocalSymbol> .GetInstance();

                var loweredSwitchGoverningExpression = _localRewriter.VisitExpression(node.Expression);
                BoundDecisionDag decisionDag         = ShareTempsIfPossibleAndEvaluateInput(
                    node.DecisionDag, loweredSwitchGoverningExpression, result, out BoundExpression savedInputExpression);

                Debug.Assert(savedInputExpression != null);

                // lower the decision dag.
                (ImmutableArray <BoundStatement> loweredDag, ImmutableDictionary <SyntaxNode, ImmutableArray <BoundStatement> > switchSections) =
                    LowerDecisionDag(decisionDag);

                // then add the rest of the lowered dag that references that input
                result.Add(_factory.Block(loweredDag));
                // A branch to the default label when no switch case matches is included in the
                // decision tree, so the code in result is unreachable at this point.

                // Lower each switch expression arm
                LocalSymbol resultTemp            = _factory.SynthesizedLocal(node.Type, node.Syntax, kind: SynthesizedLocalKind.SwitchCasePatternMatching);
                LabelSymbol afterSwitchExpression = _factory.GenerateLabel("afterSwitchExpression");

                foreach (BoundSwitchExpressionArm arm in node.SwitchArms)
                {
                    _factory.Syntax = arm.Syntax;
                    var sectionBuilder = ArrayBuilder <BoundStatement> .GetInstance();

                    sectionBuilder.AddRange(switchSections[arm.Syntax]);
                    sectionBuilder.Add(_factory.Label(arm.Label));
                    sectionBuilder.Add(_factory.Assignment(_factory.Local(resultTemp), _localRewriter.VisitExpression(arm.Value)));
                    sectionBuilder.Add(_factory.Goto(afterSwitchExpression));
                    var statements = sectionBuilder.ToImmutableAndFree();
                    if (arm.Locals.IsEmpty)
                    {
                        result.Add(_factory.StatementList(statements));
                    }
                    else
                    {
                        // Lifetime of these locals is expanded to the entire switch body, as it is possible to
                        // share them as temps in the decision dag.
                        outerVariables.AddRange(arm.Locals);

                        // Note the language scope of the locals, even though they are included for the purposes of
                        // lifetime analysis in the enclosing scope.
                        result.Add(new BoundScope(arm.Syntax, arm.Locals, statements));
                    }
                }

                _factory.Syntax = node.Syntax;
                if (node.DefaultLabel != null)
                {
                    result.Add(_factory.Label(node.DefaultLabel));
                    var objectType       = _factory.SpecialType(SpecialType.System_Object);
                    var thrownExpression =
                        (implicitConversionExists(savedInputExpression, objectType) &&
                         _factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctorObject, isOptional: true) is MethodSymbol exception1)
                            ? _factory.New(exception1, _factory.Convert(objectType, savedInputExpression)) :
                        (_factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctor, isOptional: true) is MethodSymbol exception0)
                            ? _factory.New(exception0) :
                        _factory.New(_factory.WellKnownMethod(WellKnownMember.System_InvalidOperationException__ctor));
                    result.Add(_factory.Throw(thrownExpression));
                }

                result.Add(_factory.Label(afterSwitchExpression));
                outerVariables.Add(resultTemp);
                outerVariables.AddRange(_tempAllocator.AllTemps());
                return(_factory.SpillSequence(outerVariables.ToImmutableAndFree(), result.ToImmutableAndFree(), _factory.Local(resultTemp)));

                bool implicitConversionExists(BoundExpression expression, TypeSymbol type)
                {
                    HashSet <DiagnosticInfo> discarded = null;
                    Conversion c = _localRewriter._compilation.Conversions.ClassifyConversionFromExpression(expression, type, ref discarded);

                    return(c.IsImplicit);
                }
            }
 private SwitchExpressionLocalRewriter(BoundSwitchExpression node, LocalRewriter localRewriter)
     : base(node.Syntax, localRewriter, node.SwitchArms.SelectAsArray(arm => arm.Syntax), isSwitchStatement: false)
 {
 }