private BoundStatement MakeSwitchStatementWithNonNullableExpression(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenExpression,
            ImmutableArray <BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray <LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(!rewrittenExpression.Type.IsNullableType());
            Debug.Assert((object)oldNode.StringEquality == null);

            // 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 (rewrittenExpression.Type.SpecialType == SpecialType.System_String)
            {
                EnsureStringHashFunction(rewrittenSections, syntax);
                stringEquality = GetSpecialTypeMethod(syntax, SpecialMember.System_String__op_Equality);
            }

            return(oldNode.Update(
                       boundExpression: rewrittenExpression,
                       constantTargetOpt: constantTargetOpt,
                       innerLocals: locals,
                       switchSections: rewrittenSections,
                       breakLabel: breakLabel,
                       stringEquality: stringEquality));
        }
Example #2
0
 public override BoundStatement InstrumentSwitchStatement(
     BoundSwitchStatement original,
     BoundStatement rewritten
     )
 {
     return(Previous.InstrumentSwitchStatement(original, rewritten));
 }
Example #3
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     AddAll(node.InnerLocals);
     base.VisitSwitchStatement(node);
     RemoveAll(node.InnerLocals);
     return(null);
 }
        // Rewriting for integral and string switch statements.
        // 
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class. 
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash synthesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.Expression);
            var rewrittenSections = VisitSwitchSections(node.SwitchSections);

            // EnC: We need to insert a hidden sequence point to handle function remapping in case 
            // the containing method is edited while methods invoked in the expression are being executed.
            if (!node.WasCompilerGenerated && this.Instrument)
            {
                rewrittenExpression = _instrumenter.InstrumentSwitchStatementExpression(node, rewrittenExpression, _factory);
            }

            var rewrittenStatement = MakeSwitchStatement(syntax, rewrittenExpression, rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.InnerLocalFunctions, node.BreakLabel, node);

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.Instrument && !node.WasCompilerGenerated)
            {
                rewrittenStatement = _instrumenter.InstrumentSwitchStatement(node, rewrittenStatement);
            }

            return rewrittenStatement;
        }
        // Rewriting for integral and string switch statements.
        //
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class.
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash synthesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.Expression);
            var rewrittenSections   = VisitSwitchSections(node.SwitchSections);

            // EnC: We need to insert a hidden sequence point to handle function remapping in case
            // the containing method is edited while methods invoked in the expression are being executed.
            var rewrittenStatement = MakeSwitchStatement(syntax, AddConditionSequencePoint(rewrittenExpression, node), rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.InnerLocalFunctions, node.BreakLabel, node);

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.GenerateDebugInfo && !node.WasCompilerGenerated)
            {
                SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)syntax;
                TextSpan switchSequencePointSpan   = TextSpan.FromBounds(
                    switchSyntax.SwitchKeyword.SpanStart,
                    switchSyntax.CloseParenToken.Span.End);

                return(new BoundSequencePointWithSpan(
                           syntax: syntax,
                           statementOpt: rewrittenStatement,
                           span: switchSequencePointSpan,
                           hasErrors: false));
            }

            return(rewrittenStatement);
        }
Example #6
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            // dispatch to the switch sections
            var initialState = VisitSwitchStatementDispatch(node);

            // visit switch sections
            var afterSwitchState = UnreachableState();
            var switchSections   = node.SwitchSections;
            var iLastSection     = (switchSections.Length - 1);

            for (var iSection = 0; iSection <= iLastSection; iSection++)
            {
                VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
                // Even though it is illegal for the end of a switch section to be reachable, in erroneous
                // code it may be reachable.  We treat that as an implicit break (branch to afterSwitchState).
                Join(ref afterSwitchState, ref this.State);
            }

            if (node.DecisionDag.ReachableLabels.Contains(node.BreakLabel) ||
                (node.DefaultLabel == null && node.Expression.ConstantValue == null && IsTraditionalSwitch(node)))
            {
                Join(ref afterSwitchState, ref initialState);
            }

            ResolveBreaks(afterSwitchState, node.BreakLabel);

            return(null);
        }
        // Rewriting for integral and string switch statements.
        // 
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class. 
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash synthesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.BoundExpression);
            var rewrittenSections = VisitSwitchSections(node.SwitchSections);

            // EnC: We need to insert a hidden sequence point to handle function remapping in case 
            // the containing method is edited while methods invoked in the expression are being executed.
            var rewrittenStatement = MakeSwitchStatement(syntax, AddConditionSequencePoint(rewrittenExpression, node), rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.BreakLabel, node);

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.GenerateDebugInfo && !node.WasCompilerGenerated)
            {
                SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)syntax;
                TextSpan switchSequencePointSpan = TextSpan.FromBounds(
                    switchSyntax.SwitchKeyword.SpanStart,
                    switchSyntax.CloseParenToken.Span.End);

                return new BoundSequencePointWithSpan(
                    syntax: syntax,
                    statementOpt: rewrittenStatement,
                    span: switchSequencePointSpan,
                    hasErrors: false);
            }

            return rewrittenStatement;
        }
Example #8
0
        /// <summary>
        /// Is the switch statement one that could be interpreted as a C# 6 or earlier switch statement?
        /// </summary>
        private bool IsTraditionalSwitch(BoundSwitchStatement node)
        {
            // Before recursive patterns were introduced, we did not consider handling both 'true' and 'false' to
            // completely handle all case of a switch on a bool unless there was some patterny syntax or semantics
            // in the switch.  We had two different bound nodes and separate flow analysis handling for
            // "traditional" switch statements and "pattern-based" switch statements.  We simulate that behavior
            // by testing to see if this switch would have been handled under the old rules by the old compiler.

            // If we are in a recent enough language version, we treat the switch as a fully pattern-based switch
            // for the purposes of flow analysis.
            if (compilation.LanguageVersion >= MessageID.IDS_FeatureRecursivePatterns.RequiredVersion())
            {
                return(false);
            }

            if (!node.Expression.Type.IsValidV6SwitchGoverningType())
            {
                return(false);
            }

            foreach (var sectionSyntax in ((SwitchStatementSyntax)node.Syntax).Sections)
            {
                foreach (var label in sectionSyntax.Labels)
                {
                    if (label.Kind() == SyntaxKind.CasePatternSwitchLabel)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        protected override LocalState VisitSwitchStatementDispatch(BoundSwitchStatement node)
        {
            // first, learn from any null tests in the patterns
            int slot = 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
            var        expressionState = VisitRvalueWithState(node.Expression);
            LocalState initialState    = this.State.Clone();
            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));
                }
            }

            labelStateMap.Free();
            return(initialState);
        }
Example #10
0
 public virtual BoundExpression InstrumentSwitchStatementExpression(BoundSwitchStatement original, BoundExpression rewrittenExpression, SyntheticBoundNodeFactory factory)
 {
     Debug.Assert(!original.WasCompilerGenerated);
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement);
     Debug.Assert(factory != null);
     return(rewrittenExpression);
 }
        // Rewriting for integral and string switch statements.
        // 
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeleled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class. 
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash sythesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.BoundExpression);
            var rewrittenSections = VisitSwitchSections(node.SwitchSections);

            var rewrittenStatement = MakeSwitchStatement(syntax, AddConditionSequencePoint(rewrittenExpression, node), rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.BreakLabel, node);

            if (!node.OuterLocals.IsEmpty)
            {
                rewrittenStatement = new BoundBlock(syntax, node.OuterLocals, ImmutableArray.Create(rewrittenStatement));
            }

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.generateDebugInfo && !node.WasCompilerGenerated)
            {
                SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)syntax;
                TextSpan switchSequencePointSpan = TextSpan.FromBounds(
                    switchSyntax.SwitchKeyword.SpanStart,
                    switchSyntax.CloseParenToken.Span.End);

                return new BoundSequencePointWithSpan(
                    syntax: syntax,
                    statementOpt: rewrittenStatement,
                    span: switchSequencePointSpan,
                    hasErrors: false);
            }

            return rewrittenStatement;
        }
        // Rewriting for integral and string switch statements.
        //
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class.
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash synthesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.Expression);
            var rewrittenSections   = VisitSwitchSections(node.SwitchSections);

            // EnC: We need to insert a hidden sequence point to handle function remapping in case
            // the containing method is edited while methods invoked in the expression are being executed.
            if (!node.WasCompilerGenerated && this.Instrument)
            {
                rewrittenExpression = _instrumenter.InstrumentSwitchStatementExpression(node, rewrittenExpression, _factory);
            }

            var rewrittenStatement = MakeSwitchStatement(syntax, rewrittenExpression, rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.InnerLocalFunctions, node.BreakLabel, node);

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.Instrument && !node.WasCompilerGenerated)
            {
                rewrittenStatement = _instrumenter.InstrumentSwitchStatement(node, rewrittenStatement);
            }

            return(rewrittenStatement);
        }
        // Rewriting for integral and string switch statements.
        //
        // For switch statements, we have an option of completely rewriting the switch header
        // and switch sections into simpler constructs, i.e. we can rewrite the switch header
        // using bound conditional goto statements and the rewrite the switch sections into
        // bound labeleled statements.

        // However, all the logic for emitting the switch jump tables is language agnostic
        // and includes IL optimizations. Hence we delay the switch jump table generation
        // till the emit phase. This way we also get additional benefit of sharing this code
        // between both VB and C# compilers.

        // For integral switch statements, we delay almost all the work
        // to the emit phase.

        // For string switch statements, we need to determine if we are generating a hash
        // table based jump table or a non hash jump table, i.e. linear string comparisons
        // with each case label. We use the Dev10 Heuristic to determine this
        // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
        // If we are generating a hash table based jump table, we use a simple customizable
        // hash function to hash the string constants corresponding to the case labels.
        // See SwitchStringJumpTableEmitter.ComputeStringHash().
        // We need to emit this function to compute the hash value into the compiler generate
        // <PrivateImplementationDetails> class.
        // If we have at least one string switch statement in a module that needs a
        // hash table based jump table, we generate a single public string hash sythesized method
        // that is shared across the module.

        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var syntax = node.Syntax;

            var rewrittenExpression = (BoundExpression)Visit(node.BoundExpression);
            var rewrittenSections   = VisitSwitchSections(node.SwitchSections);

            var rewrittenStatement = MakeSwitchStatement(syntax, AddConditionSequencePoint(rewrittenExpression, node), rewrittenSections, node.ConstantTargetOpt, node.InnerLocals, node.BreakLabel, node);

            // Create the sequence point if generating debug info and
            // node is not compiler generated
            if (this.GenerateDebugInfo && !node.WasCompilerGenerated)
            {
                SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)syntax;
                TextSpan switchSequencePointSpan   = TextSpan.FromBounds(
                    switchSyntax.SwitchKeyword.SpanStart,
                    switchSyntax.CloseParenToken.Span.End);

                return(new BoundSequencePointWithSpan(
                           syntax: syntax,
                           statementOpt: rewrittenStatement,
                           span: switchSequencePointSpan,
                           hasErrors: false));
            }

            return(rewrittenStatement);
        }
        private BoundStatement MakeSwitchStatementWithNullableExpression(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenExpression,
            ImmutableArray <BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray <LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(rewrittenExpression.Type.IsNullableType());

            var exprSyntax       = rewrittenExpression.Syntax;
            var exprNullableType = rewrittenExpression.Type;

            var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance();

            // Rewrite the nullable expression to a temp as we might have a user defined conversion from source expression to switch governing type.
            // We can avoid generating the temp if the expression is a bound local.
            LocalSymbol tempLocal;

            if (rewrittenExpression.Kind != BoundKind.Local)
            {
                BoundAssignmentOperator assignmentToTemp;
                BoundLocal boundTemp      = this.factory.StoreToTemp(rewrittenExpression, out assignmentToTemp);
                var        tempAssignment = new BoundExpressionStatement(exprSyntax, assignmentToTemp);
                statementBuilder.Add(tempAssignment);
                tempLocal           = boundTemp.LocalSymbol;
                rewrittenExpression = boundTemp;
            }
            else
            {
                tempLocal = null;
            }

            // Generate a BoundConditionalGoto with null check as the conditional expression and appropriate switch label as the target: null, default or exit label.
            BoundStatement condGotoNullValueTargetLabel = new BoundConditionalGoto(
                exprSyntax,
                condition: MakeNullCheck(exprSyntax, rewrittenExpression, BinaryOperatorKind.NullableNullEqual),
                jumpIfTrue: true,
                label: GetNullValueTargetSwitchLabel(rewrittenSections, breakLabel));

            statementBuilder.Add(condGotoNullValueTargetLabel);

            // Rewrite the switch statement using nullable expression's underlying value as the switch expression.

            // rewrittenExpression.GetValueOrDefault()
            MethodSymbol getValueOrDefault     = GetNullableMethod(syntax, exprNullableType, SpecialMember.System_Nullable_T_GetValueOrDefault);
            BoundCall    callGetValueOrDefault = BoundCall.Synthesized(exprSyntax, rewrittenExpression, getValueOrDefault);

            rewrittenExpression = callGetValueOrDefault;

            // rewrite switch statement
            BoundStatement rewrittenSwitchStatement = MakeSwitchStatementWithNonNullableExpression(syntax,
                                                                                                   rewrittenExpression, rewrittenSections, constantTargetOpt, locals, breakLabel, oldNode);

            statementBuilder.Add(rewrittenSwitchStatement);

            return(new BoundBlock(syntax, locals: (object)tempLocal == null ? ImmutableArray <LocalSymbol> .Empty : ImmutableArray.Create <LocalSymbol>(tempLocal), statements: statementBuilder.ToImmutableAndFree()));
        }
Example #15
0
 public virtual BoundStatement InstrumentSwitchStatement(
     BoundSwitchStatement original,
     BoundStatement rewritten
     )
 {
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement);
     return(InstrumentStatement(original, rewritten));
 }
            public static BoundStatement Rewrite(LocalRewriter localRewriter, BoundSwitchStatement node)
            {
                var            rewriter = new SwitchStatementLocalRewriter(node, localRewriter);
                BoundStatement result   = rewriter.LowerSwitchStatement(node);

                rewriter.Free();
                return(result);
            }
Example #17
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            BoundSpillSequence2 ss = null;
            BoundExpression     boundExpression = VisitExpression(ref ss, node.BoundExpression);
            ImmutableArray <BoundSwitchSection> switchSections = (ImmutableArray <BoundSwitchSection>) this.VisitList(node.SwitchSections);

            return(UpdateStatement(ss, node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, node.BreakLabel, node.StringEquality)));
        }
Example #18
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     if (IsInside)
     {
         _labelsInside.Add(node.BreakLabel);
     }
     return(base.VisitSwitchStatement(node));
 }
Example #19
0
        protected virtual TLocalState VisitSwitchStatementDispatch(BoundSwitchStatement node)
        {
            // visit switch header
            VisitRvalue(node.Expression);

            TLocalState initialState = this.State.Clone();

            var reachableLabels = node.DecisionDag.ReachableLabels;

            foreach (var section in node.SwitchSections)
            {
                foreach (var label in section.SwitchLabels)
                {
                    if (
                        reachableLabels.Contains(label.Label) ||
                        label.HasErrors ||
                        label == node.DefaultLabel &&
                        node.Expression.ConstantValue == null &&
                        IsTraditionalSwitch(node)
                        )
                    {
                        SetState(initialState.Clone());
                    }
                    else
                    {
                        SetUnreachable();
                    }

                    VisitPattern(label.Pattern);
                    SetState(StateWhenTrue);
                    if (label.WhenClause != null)
                    {
                        VisitCondition(label.WhenClause);
                        SetState(StateWhenTrue);
                    }

                    PendingBranches.Add(new PendingBranch(label, this.State, label.Label));
                }
            }

            TLocalState afterSwitchState = UnreachableState();

            if (
                node.DecisionDag.ReachableLabels.Contains(node.BreakLabel) ||
                (
                    node.DefaultLabel == null &&
                    node.Expression.ConstantValue == null &&
                    IsTraditionalSwitch(node)
                )
                )
            {
                Join(ref afterSwitchState, ref initialState);
            }

            return(afterSwitchState);
        }
Example #20
0
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            EnterStatement(node);

            BoundSpillSequenceBuilder builder = null;
            var boundExpression = VisitExpression(ref builder, node.BoundExpression);
            var switchSections  = this.VisitList(node.SwitchSections);

            return(UpdateStatement(builder, node.Update(boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, node.BreakLabel, node.StringEquality), substituteTemps: true));
        }
Example #21
0
                public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
                {
                    var oldScope = _currentScope;

                    _currentScope = CreateOrReuseScope(node, node.InnerLocals);
                    var result = base.VisitSwitchStatement(node);

                    _currentScope = oldScope;
                    return(result);
                }
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            // visit switch header
            VisitRvalue(node.Expression);

            // visit switch block
            VisitSwitchBlock(node);

            return(null);
        }
        private LocalState VisitSwitchHeader(BoundSwitchStatement node)
        {
            // Initial value for the Break state for a switch statement is established as follows:
            //  Break state = UnreachableState if either of the following is true:
            //  (1) there is a default label, or
            //  (2) the switch expression is constant and there is a matching case label.
            //  Otherwise, the Break state = current state.

            // visit switch expression
            VisitRvalue(node.Expression);
            LocalState breakState = this.State;

            // For a switch statement, we simulate a possible jump to the switch labels to ensure that
            // the label is not treated as an unused label and a pending branch to the label is noted.

            // However, if switch expression is a constant, we must have determined the single target label
            // at bind time, i.e. node.ConstantTargetOpt, and we must simulate a jump only to this label.

            var constantTargetOpt = node.ConstantTargetOpt;

            if ((object)constantTargetOpt == null)
            {
                bool hasDefaultLabel = false;
                foreach (var section in node.SwitchSections)
                {
                    foreach (var boundSwitchLabel in section.SwitchLabels)
                    {
                        var label = boundSwitchLabel.Label;
                        hasDefaultLabel = hasDefaultLabel || boundSwitchLabel.ConstantValueOpt == null;
                        SetState(breakState.Clone());
                        var simulatedGoto = new BoundGotoStatement(node.Syntax, label);
                        VisitGotoStatement(simulatedGoto);
                    }
                }

                if (hasDefaultLabel)
                {
                    // Condition (1) for an unreachable break state is satisfied
                    breakState = UnreachableState();
                }
            }
            else if (!node.BreakLabel.Equals(constantTargetOpt))
            {
                SetState(breakState.Clone());
                var simulatedGoto = new BoundGotoStatement(node.Syntax, constantTargetOpt);
                VisitGotoStatement(simulatedGoto);

                // Condition (1) or (2) for an unreachable break state is satisfied
                breakState = UnreachableState();
            }

            return(breakState);
        }
Example #24
0
 private SwitchStatementLocalRewriter(
     BoundSwitchStatement node,
     LocalRewriter localRewriter
     )
     : base(
         node.Syntax,
         localRewriter,
         node.SwitchSections.SelectAsArray(section => section.Syntax),
         // Only add instrumentation (such as sequence points) if the node is not compiler-generated.
         generateInstrumentation: localRewriter.Instrument && !node.WasCompilerGenerated
         )
 {
 }
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            // visit switch header
            LocalState breakState = VisitSwitchHeader(node);

            SetUnreachable();

            // visit switch block
            VisitSwitchBlock(node);
            IntersectWith(ref breakState, ref this.State);
            ResolveBreaks(breakState, node.BreakLabel);
            return(null);
        }
Example #26
0
        public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
        {
            SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)original.Syntax;
            TextSpan switchSequencePointSpan   = TextSpan.FromBounds(
                switchSyntax.SwitchKeyword.SpanStart,
                switchSyntax.CloseParenToken.Span.End);

            return(new BoundSequencePointWithSpan(
                       syntax: switchSyntax,
                       statementOpt: base.InstrumentSwitchStatement(original, rewritten),
                       span: switchSequencePointSpan,
                       hasErrors: false));
        }
        private void VisitSwitchBlock(BoundSwitchStatement node)
        {
            var initialState    = State.Clone();
            var reachableLabels = node.DecisionDag.ReachableLabels;

            foreach (var section in node.SwitchSections)
            {
                foreach (var label in section.SwitchLabels)
                {
                    if (reachableLabels.Contains(label.Label) || label.HasErrors ||
                        label == node.DefaultLabel && node.Expression.ConstantValue == null && IsTraditionalSwitch(node))
                    {
                        SetState(initialState.Clone());
                    }
                    else
                    {
                        SetUnreachable();
                    }

                    VisitPattern(label.Pattern);
                    SetState(StateWhenTrue);
                    if (label.WhenClause != null)
                    {
                        VisitCondition(label.WhenClause);
                        SetState(StateWhenTrue);
                    }

                    PendingBranches.Add(new PendingBranch(label, this.State, label.Label));
                }
            }

            // visit switch sections
            var afterSwitchState = UnreachableState();
            var switchSections   = node.SwitchSections;
            var iLastSection     = (switchSections.Length - 1);

            for (var iSection = 0; iSection <= iLastSection; iSection++)
            {
                VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
                // Even though it is illegal for the end of a switch section to be reachable, in erroneous
                // code it may be reachable.  We treat that as an implicit break (branch to afterSwitchState).
                Join(ref afterSwitchState, ref this.State);
            }

            if (reachableLabels.Contains(node.BreakLabel) || node.DefaultLabel == null && IsTraditionalSwitch(node))
            {
                Join(ref afterSwitchState, ref initialState);
            }

            ResolveBreaks(afterSwitchState, node.BreakLabel);
        }
        private BoundStatement MakeSwitchStatement(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenExpression,
            ImmutableArray<BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray<LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(oldNode != null);
            Debug.Assert((object)rewrittenExpression.Type != null);

            return rewrittenExpression.Type.IsNullableType() ?
                MakeSwitchStatementWithNullableExpression(syntax, rewrittenExpression, rewrittenSections, constantTargetOpt, locals, breakLabel, oldNode) :
                MakeSwitchStatementWithNonNullableExpression(syntax, null, rewrittenExpression, rewrittenSections, constantTargetOpt, locals, breakLabel, oldNode);
        }
        private BoundStatement MakeSwitchStatement(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenExpression,
            ImmutableArray <BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray <LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(oldNode != null);
            Debug.Assert((object)rewrittenExpression.Type != null);

            return(rewrittenExpression.Type.IsNullableType() ?
                   MakeSwitchStatementWithNullableExpression(syntax, rewrittenExpression, rewrittenSections, constantTargetOpt, locals, breakLabel, oldNode) :
                   MakeSwitchStatementWithNonNullableExpression(syntax, rewrittenExpression, rewrittenSections, constantTargetOpt, locals, breakLabel, oldNode));
        }
Example #30
0
            public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
            {
                var locals = node.InnerLocals;

                if (locals.IsEmpty)
                {
                    // no variables declared inside the switch statement.
                    return(base.VisitSwitchStatement(node));
                }

                var previousBlock = PushBlock(node, locals);
                var result        = base.VisitSwitchStatement(node);

                PopBlock(previousBlock);
                return(result);
            }
Example #31
0
                public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
                {
                    if (node.InnerLocals.IsDefaultOrEmpty)
                    {
                        // Skip introducing a new scope if there are no new locals
                        return(base.VisitSwitchStatement(node));
                    }

                    var oldScope = _currentScope;

                    _currentScope = CreateOrReuseScope(node, node.InnerLocals);
                    var result = base.VisitSwitchStatement(node);

                    _currentScope = oldScope;
                    return(result);
                }
        private void VisitSwitchBlock(BoundSwitchStatement node)
        {
            var afterSwitchState = UnreachableState();
            var switchSections   = node.SwitchSections;
            var iLastSection     = (switchSections.Length - 1);

            // visit switch sections
            for (var iSection = 0; iSection <= iLastSection; iSection++)
            {
                VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
                // Even though it is illegal for the end of a switch section to be reachable, in erroneous
                // code it may be reachable.  We treat that as an implicit break (branch to afterSwitchState).
                IntersectWith(ref afterSwitchState, ref this.State);
            }

            SetState(afterSwitchState);
        }
        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);
        }
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            // dispatch to the switch sections
            var(initialState, afterSwitchState) = VisitSwitchStatementDispatch(node);

            // visit switch sections
            var switchSections = node.SwitchSections;
            var iLastSection   = (switchSections.Length - 1);

            for (var iSection = 0; iSection <= iLastSection; iSection++)
            {
                VisitSwitchSection(switchSections[iSection], iSection == iLastSection);
                // Even though it is illegal for the end of a switch section to be reachable, in erroneous
                // code it may be reachable.  We treat that as an implicit break (branch to afterSwitchState).
                Join(ref afterSwitchState, ref this.State);
            }

            ResolveBreaks(afterSwitchState, node.BreakLabel);

            return(null);
        }
        private BoundStatement MakeSwitchStatementWithNonNullableExpression(
            CSharpSyntaxNode syntax,
            BoundStatement preambleOpt,
            BoundExpression rewrittenExpression,
            ImmutableArray<BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray<LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(!rewrittenExpression.Type.IsNullableType());
            Debug.Assert((object)oldNode.StringEquality == null);

            // 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 (rewrittenExpression.Type.SpecialType == SpecialType.System_String)
            {
                EnsureStringHashFunction(rewrittenSections, syntax);
                stringEquality = GetSpecialTypeMethod(syntax, SpecialMember.System_String__op_Equality);
            }

            return oldNode.Update(
                loweredPreambleOpt: preambleOpt,
                boundExpression: rewrittenExpression,
                constantTargetOpt: constantTargetOpt,
                innerLocals: locals,
                switchSections: rewrittenSections,
                breakLabel: breakLabel,
                stringEquality: stringEquality);
        }
Example #36
0
 public virtual BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement);
     return InstrumentStatement(original, rewritten);
 }
            public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
            {
                var locals = node.InnerLocals;
                if (locals.IsEmpty)
                {
                    // no variables declared inside the switch statement.
                    return base.VisitSwitchStatement(node);
                }

                var previousBlock = PushBlock(node, locals);
                var result = base.VisitSwitchStatement(node);
                PopBlock(previousBlock);
                return result;
            }
Example #38
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     if (IsInside)
     {
         _labelsInside.Add(node.BreakLabel);
     }
     return base.VisitSwitchStatement(node);
 }
Example #39
0
 public override BoundExpression InstrumentSwitchStatementExpression(BoundSwitchStatement original, BoundExpression rewrittenExpression, SyntheticBoundNodeFactory factory)
 {
     return Previous.InstrumentSwitchStatementExpression(original, rewrittenExpression, factory);
 }
        private BoundStatement MakeSwitchStatementWithNullableExpression(
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenExpression,
            ImmutableArray<BoundSwitchSection> rewrittenSections,
            LabelSymbol constantTargetOpt,
            ImmutableArray<LocalSymbol> locals,
            GeneratedLabelSymbol breakLabel,
            BoundSwitchStatement oldNode)
        {
            Debug.Assert(rewrittenExpression.Type.IsNullableType());

            var exprSyntax = rewrittenExpression.Syntax;
            var exprNullableType = rewrittenExpression.Type;

            var statementBuilder = ArrayBuilder<BoundStatement>.GetInstance();

            // Rewrite the nullable expression to a temp as we might have a user defined conversion from source expression to switch governing type.
            // We can avoid generating the temp if the expression is a bound local.
            LocalSymbol tempLocal;
            if (rewrittenExpression.Kind != BoundKind.Local)
            {
                BoundAssignmentOperator assignmentToTemp;
                BoundLocal boundTemp = _factory.StoreToTemp(rewrittenExpression, out assignmentToTemp);
                var tempAssignment = new BoundExpressionStatement(exprSyntax, assignmentToTemp);
                statementBuilder.Add(tempAssignment);
                tempLocal = boundTemp.LocalSymbol;
                rewrittenExpression = boundTemp;
            }
            else
            {
                tempLocal = null;
            }

            // Generate a BoundConditionalGoto with null check as the conditional expression and appropriate switch label as the target: null, default or exit label.
            BoundStatement condGotoNullValueTargetLabel = new BoundConditionalGoto(
                exprSyntax,
                condition: MakeNullCheck(exprSyntax, rewrittenExpression, BinaryOperatorKind.NullableNullEqual),
                jumpIfTrue: true,
                label: GetNullValueTargetSwitchLabel(rewrittenSections, breakLabel));

            // Rewrite the switch statement using nullable expression's underlying value as the switch expression.

            // rewrittenExpression.GetValueOrDefault()
            MethodSymbol getValueOrDefault = GetNullableMethod(syntax, exprNullableType, SpecialMember.System_Nullable_T_GetValueOrDefault);
            BoundCall callGetValueOrDefault = BoundCall.Synthesized(exprSyntax, rewrittenExpression, getValueOrDefault);
            rewrittenExpression = callGetValueOrDefault;

            // rewrite switch statement
            BoundStatement rewrittenSwitchStatement = MakeSwitchStatementWithNonNullableExpression(
                syntax,
                condGotoNullValueTargetLabel,
                rewrittenExpression,
                rewrittenSections,
                constantTargetOpt,
                locals,
                breakLabel,
                oldNode);

            statementBuilder.Add(rewrittenSwitchStatement);

            return new BoundBlock(syntax, locals: (object)tempLocal == null ? ImmutableArray<LocalSymbol>.Empty : ImmutableArray.Create<LocalSymbol>(tempLocal), statements: statementBuilder.ToImmutableAndFree());
        }
Example #41
0
        public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
        {
            SwitchStatementSyntax switchSyntax = (SwitchStatementSyntax)original.Syntax;
            TextSpan switchSequencePointSpan = TextSpan.FromBounds(
                switchSyntax.SwitchKeyword.SpanStart,
                switchSyntax.CloseParenToken.Span.End);

            return new BoundSequencePointWithSpan(
                syntax: switchSyntax,
                statementOpt: base.InstrumentSwitchStatement(original, rewritten),
                span: switchSequencePointSpan,
                hasErrors: false);
        }
Example #42
0
 public virtual BoundExpression InstrumentSwitchStatementExpression(BoundSwitchStatement original, BoundExpression rewrittenExpression, SyntheticBoundNodeFactory factory)
 {
     Debug.Assert(!original.WasCompilerGenerated);
     Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement);
     Debug.Assert(factory != null);
     return rewrittenExpression;
 }
Example #43
0
 public override BoundExpression InstrumentSwitchStatementExpression(BoundSwitchStatement original, BoundExpression rewrittenExpression, SyntheticBoundNodeFactory factory)
 {
     // EnC: We need to insert a hidden sequence point to handle function remapping in case 
     // the containing method is edited while methods invoked in the expression are being executed.
     return AddConditionSequencePoint(base.InstrumentSwitchStatementExpression(original, rewrittenExpression, factory), original.Syntax, factory);
 }
Example #44
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     BoundSpillSequence2 ss = null;
     BoundExpression boundExpression = VisitExpression(ref ss, node.BoundExpression);
     ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections);
     return UpdateStatement(ss, node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, node.BreakLabel, node.StringEquality));
 }
Example #45
0
 public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     return AddDynamicAnalysis(original, base.InstrumentSwitchStatement(original, rewritten));
 }
            // For switch statements, we have an option of completely rewriting the switch header
            // and switch sections into simpler constructs, i.e. we can rewrite the switch header
            // using bound conditional goto statements and the rewrite the switch sections into
            // bound labeled statements.
            //
            // However, all the logic for emitting the switch jump tables is language agnostic
            // and includes IL optimizations. Hence we delay the switch jump table generation
            // till the emit phase. This way we also get additional benefit of sharing this code
            // between both VB and C# compilers.
            //
            // For string switch statements, we need to determine if we are generating a hash
            // table based jump table or a non hash jump table, i.e. linear string comparisons
            // with each case label. We use the Dev10 Heuristic to determine this
            // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
            // If we are generating a hash table based jump table, we use a simple
            // hash function to hash the string constants corresponding to the case labels.
            // See SwitchStringJumpTableEmitter.ComputeStringHash().
            // We need to emit this same function to compute the hash value into the compiler generated
            // <PrivateImplementationDetails> class.
            // If we have at least one string switch statement in a module that needs a
            // hash table based jump table, we generate a single public string hash synthesized method
            // that is shared across the module.
            private void LowerBasicSwitch(DecisionTree.ByValue byValue)
            {
                var switchSections = ArrayBuilder<BoundSwitchSection>.GetInstance();
                var noValueMatches = _factory.GenerateLabel("noValueMatches");
                var underlyingSwitchType = byValue.Type.IsEnumType() ? byValue.Type.GetEnumUnderlyingType() : byValue.Type;
                foreach (var vd in byValue.ValueAndDecision)
                {
                    var value = vd.Key;
                    var decision = vd.Value;
                    var constantValue = ConstantValue.Create(value, underlyingSwitchType.SpecialType);
                    var constantExpression = new BoundLiteral(_factory.Syntax, constantValue, underlyingSwitchType);
                    var label = _factory.GenerateLabel("case+" + value);
                    var switchLabel = new BoundSwitchLabel(_factory.Syntax, label, constantExpression, constantValue);
                    var forValue = ArrayBuilder<BoundStatement>.GetInstance();
                    LowerDecisionTree(byValue.Expression, decision, forValue);
                    if (!decision.MatchIsComplete)
                    {
                        forValue.Add(_factory.Goto(noValueMatches));
                    }

                    var section = new BoundSwitchSection(_factory.Syntax, ImmutableArray.Create(switchLabel), forValue.ToImmutableAndFree());
                    switchSections.Add(section);
                }

                var rewrittenSections = switchSections.ToImmutableAndFree();
                MethodSymbol stringEquality = null;
                if (underlyingSwitchType.SpecialType == SpecialType.System_String)
                {
                    LocalRewriter.EnsureStringHashFunction(rewrittenSections, _factory.Syntax);
                    stringEquality = LocalRewriter.GetSpecialTypeMethod(_factory.Syntax, SpecialMember.System_String__op_Equality);
                }

                // The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
                var constantTarget = rewrittenSections.IsEmpty ? noValueMatches : null;
                var switchStatement = new BoundSwitchStatement(
                    _factory.Syntax, null, _factory.Convert(underlyingSwitchType, byValue.Expression),
                    constantTarget,
                    ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty,
                    rewrittenSections, noValueMatches, stringEquality);
                // The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.

                switch (underlyingSwitchType.SpecialType)
                {
                    case SpecialType.System_Boolean:
                        // boolean switch is handled in LowerBooleanSwitch, not here.
                        throw ExceptionUtilities.Unreachable;

                    case SpecialType.System_String:
                    case SpecialType.System_Byte:
                    case SpecialType.System_Char:
                    case SpecialType.System_Int16:
                    case SpecialType.System_Int32:
                    case SpecialType.System_Int64:
                    case SpecialType.System_SByte:
                    case SpecialType.System_UInt16:
                    case SpecialType.System_UInt32:
                    case SpecialType.System_UInt64:
                        {
                            // emit knows how to efficiently generate code for these kinds of switches.
                            _loweredDecisionTree.Add(switchStatement);
                            break;
                        }

                    default:
                        {
                            // other types, such as float, double, and decimal, are not currently
                            // handled by emit and must be lowered here.
                            _loweredDecisionTree.Add(LowerNonprimitiveSwitch(switchStatement));
                            break;
                        }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     CollectLabel(node.ConstantTargetOpt);
     CollectLabel(node.BreakLabel);
     return base.VisitSwitchStatement(node);
 }
Example #48
0
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     AddTarget(node.BreakLabel);
     return base.VisitSwitchStatement(node);
 }
Example #49
0
 public override BoundStatement InstrumentSwitchStatement(BoundSwitchStatement original, BoundStatement rewritten)
 {
     return Previous.InstrumentSwitchStatement(original, rewritten);
 }
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     Debug.Assert(node.OuterLocals.IsEmpty);
     return PossibleIteratorScope(node.InnerLocals, () => (BoundStatement)base.VisitSwitchStatement(node));
 }
 public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
 {
     return PossibleIteratorScope(node.LocalsOpt, () => (BoundStatement)base.VisitSwitchStatement(node));
 }
            private BoundStatement LowerNonprimitiveSwitch(BoundSwitchStatement switchStatement)
            {
                // Here we handle "other" types, such as float, double, and decimal, by
                // lowering the BoundSwitchStatement.
                // We compare the constant values using value.Equals(input), using ordinary
                // overload resolution. Note that we cannot and do not rely on switching
                // on the hash code, as it may not be consistent with the behavior of Equals;
                // see https://github.com/dotnet/coreclr/issues/6237. Also, the hash code is
                // not guaranteed to be the same on the compilation platform as the runtime
                // platform.
                // CONSIDER: can we improve the quality of the code using comparisons, like
                //           we do for other numeric types, by generating a series of tests
                //           that use divide-and-conquer to efficiently find a matching value?
                //           If so, we should use the BoundSwitchStatement and do that in emit.
                //           Moreover, we should be able to use `==` rather than `.Equals`
                //           for cases (such as non-NaN) where we know the result to be the same.
                var rewrittenSections = switchStatement.SwitchSections;
                var expression = switchStatement.Expression;
                var noValueMatches = switchStatement.BreakLabel;
                Debug.Assert(switchStatement.LoweredPreambleOpt == null);
                Debug.Assert(switchStatement.InnerLocals.IsDefaultOrEmpty);
                Debug.Assert(switchStatement.InnerLocalFunctions.IsDefaultOrEmpty);
                Debug.Assert(switchStatement.StringEquality == null);
                LabelSymbol nextLabel = null;
                var builder = ArrayBuilder<BoundStatement>.GetInstance();
                foreach (var section in rewrittenSections)
                {
                    foreach (var boundSwitchLabel in section.SwitchLabels)
                    {
                        if (nextLabel != null)
                        {
                            builder.Add(_factory.Label(nextLabel));
                        }
                        nextLabel = _factory.GenerateLabel("failcase+" + section.SwitchLabels[0].ConstantValueOpt.Value);

                        Debug.Assert(boundSwitchLabel.ConstantValueOpt != null);
                        // generate (if (value.Equals(input)) goto label;
                        var literal = LocalRewriter.MakeLiteral(_factory.Syntax, boundSwitchLabel.ConstantValueOpt, expression.Type);
                        var condition = _factory.InstanceCall(literal, "Equals", expression);
                        if (!condition.HasErrors && condition.Type.SpecialType != SpecialType.System_Boolean)
                        {
                            var call = (BoundCall)condition;
                            // '{1} {0}' has the wrong return type
                            _factory.Diagnostics.Add(ErrorCode.ERR_BadRetType, boundSwitchLabel.Syntax.GetLocation(), call.Method, call.Type);
                        }

                        builder.Add(_factory.ConditionalGoto(condition, boundSwitchLabel.Label, true));
                        builder.Add(_factory.Goto(nextLabel));
                    }

                    foreach (var boundSwitchLabel in section.SwitchLabels)
                    {
                        builder.Add(_factory.Label(boundSwitchLabel.Label));
                    }

                    builder.Add(_factory.Block(section.Statements));
                    // this location should not be reachable.
                }

                Debug.Assert(nextLabel != null);
                builder.Add(_factory.Label(nextLabel));
                builder.Add(_factory.Label(noValueMatches));
                return _factory.Block(builder.ToImmutableAndFree());
            }
        public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
        {
            var expression = (BoundExpression)this.Visit(node.BoundExpression);
            ReadOnlyArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections);

            if (expression.Kind != BoundKind.SpillSequence)
            {
                return node.Update(expression, node.ConstantTargetOpt, node.LocalsOpt, switchSections, node.BreakLabel);
            }
            
            var spill = (BoundSpillSequence)expression;

            var newSwitchStatement = node.Update(
                    spill.Value,
                    node.ConstantTargetOpt,
                    node.LocalsOpt,
                    switchSections,
                    node.BreakLabel);

            return RewriteSpillSequenceAsBlock(spill, newSwitchStatement);
        }