internal static void AssertIsLabeledStatementWithLabel(this BoundStatement node, LabelSymbol label)
        {
            Debug.Assert(node != null);

            switch (node.Kind)
            {
                case BoundKind.LabelStatement:
                    Debug.Assert(((BoundLabelStatement)node).Label == label);
                    break;

                case BoundKind.LabeledStatement:
                    Debug.Assert(((BoundLabeledStatement)node).Label == label);
                    break;

                case BoundKind.SwitchSection:
                    foreach (var boundSwitchLabel in ((BoundSwitchSection)node).BoundSwitchLabels)
                    {
                        if (boundSwitchLabel.Label == label)
                        {
                            return;
                        }
                    }
                    throw ExceptionUtilities.Unreachable;

                default:
                    throw ExceptionUtilities.UnexpectedValue(node.Kind);
            }
        }
예제 #2
0
        internal AsyncIteratorMethodToStateMachineRewriter(MethodSymbol method,
                                                           int methodOrdinal,
                                                           AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
                                                           AsyncIteratorInfo asyncIteratorInfo,
                                                           SyntheticBoundNodeFactory F,
                                                           FieldSymbol state,
                                                           FieldSymbol builder,
                                                           IReadOnlySet <Symbol> hoistedVariables,
                                                           IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies,
                                                           SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals,
                                                           ArrayBuilder <StateMachineStateDebugInfo> stateMachineStateDebugInfoBuilder,
                                                           VariableSlotAllocator slotAllocatorOpt,
                                                           int nextFreeHoistedLocalSlot,
                                                           BindingDiagnosticBag diagnostics)
            : base(method, methodOrdinal, asyncMethodBuilderMemberCollection, F,
                   state, builder, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals,
                   stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics)
        {
            Debug.Assert(asyncIteratorInfo != null);

            _asyncIteratorInfo    = asyncIteratorInfo;
            _currentDisposalLabel = _exprReturnLabel;
            _exprReturnLabelTrue  = F.GenerateLabel("yieldReturn");

            _iteratorStateAllocator = new ResumableStateMachineStateAllocator(
                slotAllocatorOpt,
                firstState: StateMachineState.FirstResumableAsyncIteratorState,
                increasing: false);
        }
예제 #3
0
        private static LabelSymbol GetNullValueTargetSwitchLabel(ImmutableArray <BoundSwitchSection> sections, GeneratedLabelSymbol breakLabel)
        {
            LabelSymbol fallThroughLabel = breakLabel;

            foreach (var section in sections)
            {
                foreach (BoundSwitchLabel boundLabel in section.SwitchLabels)
                {
                    var label         = (SourceLabelSymbol)boundLabel.Label;
                    var labelConstant = boundLabel.ConstantValueOpt;

                    if (labelConstant == ConstantValue.Null)
                    {
                        return(label);
                    }
                    else if (labelConstant == null)
                    {
                        // Default label
                        Debug.Assert(label.IdentifierNodeOrToken.Kind() == SyntaxKind.DefaultSwitchLabel);
                        Debug.Assert(fallThroughLabel == breakLabel);

                        fallThroughLabel = label;
                    }
                }
            }

            return(fallThroughLabel);
        }
예제 #4
0
            // Can the given decision dag node, and its successors, be generated as a sequence of
            // linear tests with a single "golden" path to the true label and all other paths leading
            // to the false label?  This occurs with an is-pattern expression that uses no "or" or "not"
            // pattern forms.
            static bool canProduceLinearSequence(
                BoundDecisionDagNode node,
                LabelSymbol whenTrueLabel,
                LabelSymbol whenFalseLabel)
            {
                while (true)
                {
                    switch (node)
                    {
                    case BoundWhenDecisionDagNode w:
                        Debug.Assert(w.WhenFalse is null);
                        node = w.WhenTrue;
                        break;

                    case BoundLeafDecisionDagNode n:
                        return(n.Label == whenTrueLabel);

                    case BoundEvaluationDecisionDagNode e:
                        node = e.Next;
                        break;

                    case BoundTestDecisionDagNode t:
                        bool falseFail = IsFailureNode(t.WhenFalse, whenFalseLabel);
                        if (falseFail == IsFailureNode(t.WhenTrue, whenFalseLabel))
                        {
                            return(false);
                        }
                        node = falseFail ? t.WhenTrue : t.WhenFalse;
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(node);
                    }
                }
            }
예제 #5
0
            // returns a proxy for a label if branch must be hijacked to run finally
            // otherwise returns same label back
            public LabelSymbol ProxyLabelIfNeeded(LabelSymbol label)
            {
                // no need to proxy a label in the current frame or when we are at the root
                if (this.IsRoot() || (LabelsOpt != null && LabelsOpt.Contains(label)))
                {
                    return(label);
                }

                var proxyLabels   = this.proxyLabels;
                var proxiedLabels = this.proxiedLabels;

                if (proxyLabels == null)
                {
                    this.proxyLabels   = proxyLabels = new Dictionary <LabelSymbol, LabelSymbol>();
                    this.proxiedLabels = proxiedLabels = new List <LabelSymbol>();
                }

                LabelSymbol proxy;

                if (!proxyLabels.TryGetValue(label, out proxy))
                {
                    proxy = new GeneratedLabelSymbol("proxy" + label.Name);
                    proxyLabels.Add(label, proxy);
                    proxiedLabels.Add(label);
                }

                return(proxy);
            }
        protected override BoundStatement GenerateReturn(bool finished)
        {
            BoundLiteral result = this.F.Literal(!finished);

            if (_tryNestingLevel == 0)
            {
                return(F.Return(result));
            }
            else
            {
                if ((object)_exitLabel == null)
                {
                    _exitLabel   = this.F.GenerateLabel("exitLabel");
                    _methodValue = F.SynthesizedLocal(result.Type);
                }

                var gotoExit = F.Goto(_exitLabel);

                if (finished)
                {
                    // since we are finished, we need to treat this as a potential Leave
                    gotoExit = (BoundGotoStatement)VisitGotoStatement(gotoExit);
                }

                return(this.F.Block(
                           F.Assignment(this.F.Local(_methodValue), result),
                           gotoExit));
            }
        }
 public BoundLabelStatement Label(LabelSymbol label)
 {
     return(new BoundLabelStatement(Syntax, label)
     {
         WasCompilerGenerated = true
     });
 }
        internal static void AssertIsLabeledStatementWithLabel(this BoundStatement node, LabelSymbol label)
        {
            Debug.Assert(node != null);

            switch (node.Kind)
            {
                case BoundKind.LabelStatement:
                    Debug.Assert(((BoundLabelStatement)node).Label == label);
                    break;

                case BoundKind.LabeledStatement:
                    Debug.Assert(((BoundLabeledStatement)node).Label == label);
                    break;

                case BoundKind.SwitchSection:
                    foreach (var boundSwitchLabel in ((BoundSwitchSection)node).BoundSwitchLabels)
                    {
                        if (boundSwitchLabel.Label == label)
                        {
                            return;
                        }
                    }
                    Debug.Assert(false);
                    break;

                default:
                    Debug.Assert(false);
                    break;
            }
        }
예제 #9
0
 private void ResolveLabel(BoundNode node, LabelSymbol label)
 {
     if (node.Syntax != null && RegionContains(node.Syntax.Span))
     {
         _labelsInside.Add(label);
     }
 }
예제 #10
0
        internal AsyncMethodToStateMachineRewriter(
            MethodSymbol method,
            int methodOrdinal,
            AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
            SyntheticBoundNodeFactory F,
            FieldSymbol state,
            FieldSymbol builder,
            IReadOnlySet <Symbol> hoistedVariables,
            IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> nonReusableLocalProxies,
            SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals,
            VariableSlotAllocator slotAllocatorOpt,
            int nextFreeHoistedLocalSlot,
            DiagnosticBag diagnostics)
            : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false)
        {
            _method = method;
            _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
            _asyncMethodBuilderField            = builder;
            _exprReturnLabel = F.GenerateLabel("exprReturn");
            _exitLabel       = F.GenerateLabel("exitLabel");

            _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue)
                : null;

            _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal);
            _awaiterFields  = new Dictionary <TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicTupleNamesAndNullabilityComparer);
            _nextAwaiterId  = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0;
        }
        private BoundPatternSwitchSection BindPatternSwitchSection(
            BoundExpression boundSwitchExpression,
            SwitchSectionSyntax node,
            Binder originalBinder,
            ref BoundPatternSwitchLabel defaultLabel,
            DiagnosticBag diagnostics)
        {
            // Bind match section labels
            var boundLabelsBuilder = ArrayBuilder <BoundPatternSwitchLabel> .GetInstance();

            var sectionBinder = originalBinder.GetBinder(node); // this binder can bind pattern variables from the section.

            Debug.Assert(sectionBinder != null);
            var labelsByNode = LabelsByNode;

            foreach (var labelSyntax in node.Labels)
            {
                LabelSymbol             label      = labelsByNode[labelSyntax];
                BoundPatternSwitchLabel boundLabel = BindPatternSwitchSectionLabel(sectionBinder, boundSwitchExpression, labelSyntax, label, ref defaultLabel, diagnostics);
                boundLabelsBuilder.Add(boundLabel);
            }

            // Bind switch section statements
            var boundStatementsBuilder = ArrayBuilder <BoundStatement> .GetInstance();

            foreach (var statement in node.Statements)
            {
                boundStatementsBuilder.Add(sectionBinder.BindStatement(statement, diagnostics));
            }

            return(new BoundPatternSwitchSection(node, sectionBinder.GetDeclaredLocalsForScope(node), boundLabelsBuilder.ToImmutableAndFree(), boundStatementsBuilder.ToImmutableAndFree()));
        }
        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(
                       outerLocals: ImmutableArray <LocalSymbol> .Empty,
                       boundExpression: rewrittenExpression,
                       constantTargetOpt: constantTargetOpt,
                       innerLocals: locals,
                       switchSections: rewrittenSections,
                       breakLabel: breakLabel,
                       stringEquality: stringEquality));
        }
예제 #13
0
            public LabelSymbol ProxyReturnIfNeeded(
                MethodSymbol containingMethod,
                BoundExpression valueOpt,
                out LocalSymbol returnValue)
            {
                returnValue = null;

                // no need to proxy returns  at the root
                if (this.IsRoot())
                {
                    return(null);
                }

                var returnProxy = this.returnProxy;

                if (returnProxy == null)
                {
                    this.returnProxy = returnProxy = new GeneratedLabelSymbol("returnProxy");
                }

                if (valueOpt != null)
                {
                    returnValue = this.returnValue;
                    if (returnValue == null)
                    {
                        this.returnValue = returnValue = new SynthesizedLocal(containingMethod, valueOpt.Type, SynthesizedLocalKind.LoweringTemp);
                    }
                }

                return(returnProxy);
            }
        internal AsyncMethodToStateMachineRewriter(
            MethodSymbol method,
            int methodOrdinal,
            AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
            SyntheticBoundNodeFactory F,
            FieldSymbol state,
            FieldSymbol builder,
            IReadOnlySet<Symbol> hoistedVariables,
            IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies,
            SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals,
            VariableSlotAllocator slotAllocatorOpt,
            int nextFreeHoistedLocalSlot,
            DiagnosticBag diagnostics)
            : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics, useFinalizerBookkeeping: false)
        {
            _method = method;
            _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
            _asyncMethodBuilderField = builder;
            _exprReturnLabel = F.GenerateLabel("exprReturn");
            _exitLabel = F.GenerateLabel("exitLabel");

            _exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, syntax: F.Syntax, kind: SynthesizedLocalKind.AsyncMethodReturnValue)
                : null;

            _dynamicFactory = new LoweredDynamicOperationFactory(F, methodOrdinal);
            _awaiterFields = new Dictionary<TypeSymbol, FieldSymbol>(TypeSymbol.EqualsIgnoringDynamicComparer);
            _nextAwaiterId = slotAllocatorOpt?.PreviousAwaiterSlotCount ?? 0;
        }
예제 #15
0
        private BoundBlock PendBranches(
            AwaitFinallyFrame frame,
            LocalSymbol pendingBranchVar,
            LabelSymbol finallyLabel)
        {
            var bodyStatements = ArrayBuilder <BoundStatement> .GetInstance();

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;
            var proxyLabels   = frame.proxyLabels;

            // skip 0 - it means we took no explicit branches
            int i = 1;

            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var proxied = proxiedLabels[i - 1];
                    var proxy   = proxyLabels[proxied];

                    PendBranch(bodyStatements, proxy, i, pendingBranchVar, finallyLabel);
                }
            }

            var returnProxy = frame.returnProxyLabel;

            if (returnProxy != null)
            {
                PendBranch(bodyStatements, returnProxy, i, pendingBranchVar, finallyLabel);
            }

            return(_F.Block(bodyStatements.ToImmutableAndFree()));
        }
예제 #16
0
            internal AsyncMethodToClassRewriter(
                MethodSymbol method,
                AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
                SyntheticBoundNodeFactory F,
                FieldSymbol state,
                FieldSymbol builder,
                HashSet<Symbol> variablesCaptured,
                Dictionary<Symbol, CapturedSymbolReplacement> initialProxies,
                DiagnosticBag diagnostics,
                bool generateDebugInfo)
                : base(F, method, state, variablesCaptured, initialProxies, diagnostics,
                      useFinalizerBookkeeping: false,
                      generateDebugInfo: generateDebugInfo)
            {
                this.method = method;
                this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
                this.asyncMethodBuilderField = builder;
                this.exprReturnLabel = F.GenerateLabel("exprReturn");
                this.exitLabel = F.GenerateLabel("exitLabel");

                this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                    ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName())
                    : null;

                this.dynamicFactory = new LoweredDynamicOperationFactory(F);
            }
예제 #17
0
        internal static void AssertIsLabeledStatementWithLabel(
            this BoundStatement node,
            LabelSymbol label
            )
        {
            Debug.Assert(node != null);

            switch (node.Kind)
            {
            case BoundKind.LabelStatement:
                Debug.Assert(((BoundLabelStatement)node).Label == label);
                break;

            case BoundKind.LabeledStatement:
                Debug.Assert(((BoundLabeledStatement)node).Label == label);
                break;

            case BoundKind.SwitchSection:
                foreach (var boundSwitchLabel in ((BoundSwitchSection)node).SwitchLabels)
                {
                    if (boundSwitchLabel.Label == label)
                    {
                        return;
                    }
                }
                throw ExceptionUtilities.Unreachable;

            default:
                throw ExceptionUtilities.UnexpectedValue(node.Kind);
            }
        }
        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()));
        }
예제 #19
0
        protected override void VisitSwitchSectionLabel(LabelSymbol label, BoundSwitchSection node)
        {
            _labelsDefined.Add(label);
            base.VisitSwitchSectionLabel(label, node);

            // switch statement labels are always considered to be referenced
            _labelsUsed.Add(label);
        }
예제 #20
0
 public BoundWhileStatement(BoundExpression condition, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel, bool addContinue = true)
 {
     Condition     = condition;
     Body          = body;
     BreakLabel    = breakLabel;
     ContinueLabel = continueLabel;
     AddContinue   = addContinue;
 }
예제 #21
0
        public static BoundBlock Lower(BoundStatement statement, LabelSymbol endLabel = null)
        {
            Lowerer lowerer = new Lowerer(endLabel);

            var lowered = lowerer.RewriteStatement(statement);

            return(Flatten(lowered));
        }
예제 #22
0
        protected override LocalState LabelState(LabelSymbol label)
        {
            LocalState result = base.LabelState(label);

            // We don't want errors reported in one pass to suppress errors in the next pass.
            result.Reported = false;
            return(result);
        }
            private void LowerWhenClause(BoundWhenDecisionDagNode whenClause)
            {
                // This node is used even when there is no when clause, to record bindings. In the case that there
                // is no when clause, whenClause.WhenExpression and whenClause.WhenFalse are null, and the syntax for this
                // node is the case clause.

                // We need to assign the pattern variables in the code where they are in scope, so we produce a branch
                // to the section where they are in scope and evaluate the when clause there.
                var         whenTrue            = (BoundLeafDecisionDagNode)whenClause.WhenTrue;
                LabelSymbol labelToSectionScope = GetDagNodeLabel(whenClause);

                // We need the section syntax to get the section builder from the map. Unfortunately this is a bit awkward
                SyntaxNode sectionSyntax       = whenClause.Syntax is SwitchLabelSyntax l ? l.Parent : whenClause.Syntax;
                bool       foundSectionBuilder = _switchArms.TryGetValue(sectionSyntax, out ArrayBuilder <BoundStatement> sectionBuilder);

                Debug.Assert(foundSectionBuilder);
                sectionBuilder.Add(_factory.Label(labelToSectionScope));
                foreach (BoundPatternBinding binding in whenClause.Bindings)
                {
                    BoundExpression left = _localRewriter.VisitExpression(binding.VariableAccess);
                    // Since a switch does not add variables to the enclosing scope, the pattern variables
                    // are locals even in a script and rewriting them should have no effect.
                    Debug.Assert(left.Kind == BoundKind.Local && left == binding.VariableAccess);
                    BoundExpression right = _tempAllocator.GetTemp(binding.TempContainingValue);
                    if (left != right)
                    {
                        sectionBuilder.Add(_factory.Assignment(left, right));
                    }
                }

                var whenFalse = whenClause.WhenFalse;
                var trueLabel = GetDagNodeLabel(whenTrue);

                if (whenClause.WhenExpression != null && whenClause.WhenExpression.ConstantValue != ConstantValue.True)
                {
                    _factory.Syntax = whenClause.Syntax;
                    BoundStatement conditionalGoto = _factory.ConditionalGoto(_localRewriter.VisitExpression(whenClause.WhenExpression), trueLabel, jumpIfTrue: true);

                    // Only add instrumentation (such as a sequence point) if the node is not compiler-generated.
                    if (IsSwitchStatement && !whenClause.WhenExpression.WasCompilerGenerated && _localRewriter.Instrument)
                    {
                        conditionalGoto = _localRewriter._instrumenter.InstrumentSwitchWhenClauseConditionalGotoBody(whenClause.WhenExpression, conditionalGoto);
                    }

                    sectionBuilder.Add(conditionalGoto);

                    Debug.Assert(whenFalse != null);

                    // We hide the jump back into the decision dag, as it is not logically part of the when clause
                    BoundStatement jump = _factory.Goto(GetDagNodeLabel(whenFalse));
                    sectionBuilder.Add(IsSwitchStatement ? _factory.HiddenSequencePoint(jump) : jump);
                }
                else
                {
                    Debug.Assert(whenFalse == null);
                    sectionBuilder.Add(_factory.Goto(trueLabel));
                }
            }
예제 #24
0
        private void AddTarget(LabelSymbol label)
        {
            if (_targets == null)
            {
                _targets = new HashSet <LabelSymbol>();
            }

            _targets.Add(label);
        }
예제 #25
0
        private void AddGoto(LabelSymbol label)
        {
            if (_gotos == null)
            {
                _gotos = new HashSet <LabelSymbol>();
            }

            _gotos.Add(label);
        }
예제 #26
0
 public BoundForStatement(BoundStatement assignment, BoundExpression condition, BoundExpression step, BoundStatement body, LabelSymbol breakLabel, LabelSymbol continueLabel)
 {
     Assignment    = assignment;
     Condition     = condition;
     Step          = step;
     Body          = body;
     BreakLabel    = breakLabel;
     ContinueLabel = continueLabel;
 }
        // Rewriting for pattern-matching switch statements.
        public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node)
        {
            var statements = ArrayBuilder <BoundStatement> .GetInstance();

            // copy the original switch expression into a temp
            BoundAssignmentOperator initialStore;
            var switchExpressionTemp = _factory.StoreToTemp(VisitExpression(node.Expression), out initialStore, syntaxOpt: node.Expression.Syntax);

            statements.Add(_factory.ExpressionStatement(initialStore));

            // save the default label, if and when we find it.
            LabelSymbol defaultLabel = null;

            foreach (var section in node.PatternSwitchSections)
            {
                BoundExpression sectionCondition = _factory.Literal(false);
                bool            isDefaultSection = false;
                foreach (var label in section.PatternSwitchLabels)
                {
                    if (label.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel)
                    {
                        // The default label was handled in initial tail, above
                        Debug.Assert(label.Pattern.Kind == BoundKind.WildcardPattern && label.Guard == null);
                        isDefaultSection = true;
                        defaultLabel     = _factory.GenerateLabel("default");
                        continue;
                    }

                    var labelCondition = LowerPattern(label.Pattern, switchExpressionTemp);
                    if (label.Guard != null)
                    {
                        labelCondition = _factory.LogicalAnd(labelCondition, VisitExpression(label.Guard));
                    }

                    sectionCondition = _factory.LogicalOr(sectionCondition, labelCondition);
                }

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

                if (isDefaultSection)
                {
                    sectionBuilder.Add(_factory.Label(defaultLabel));
                }
                sectionBuilder.AddRange(VisitList(section.Statements));
                sectionBuilder.Add(_factory.Goto(node.BreakLabel));
                statements.Add(_factory.If(sectionCondition, section.Locals, _factory.Block(sectionBuilder.ToImmutableAndFree())));
            }

            if (defaultLabel != null)
            {
                statements.Add(_factory.Goto(defaultLabel));
            }

            statements.Add(_factory.Label(node.BreakLabel));
            return(_factory.Block(node.InnerLocals.Add(switchExpressionTemp.LocalSymbol), node.InnerLocalFunctions, statements.ToImmutableAndFree()));
        }
예제 #28
0
        protected override void ResolveBranch(PendingBranch pending, LabelSymbol label, BoundStatement target, ref bool labelStateChanged)
        {
            // branches into a region are considered entry points
            if (IsInside && pending.Branch != null && !RegionContains(pending.Branch.Syntax.Span))
            {
                pending.State = pending.State.Reachable ? TopState() : UnreachableState();
            }

            base.ResolveBranch(pending, label, target, ref labelStateChanged);
        }
예제 #29
0
        protected override void ResolveBranch(PendingBranch pending, LabelSymbol label, BoundStatement target, ref bool labelStateChanged)
        {
            // branches into a region are considered entry points
            if (IsInside && pending.Branch != null && !RegionContains(pending.Branch.Syntax.Span))
            {
                pending.State = pending.State.Reachable ? ReachableState() : UnreachableState();
            }

            base.ResolveBranch(pending, label, target, ref labelStateChanged);
        }
            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);
            }
        /// <summary>
        /// An async-iterator state machine has a flag indicating "dispose mode".
        /// We enter dispose mode by calling DisposeAsync() when the state machine is paused on a `yield return`.
        /// DisposeAsync() will resume execution of the state machine from that state (using existing dispatch mechanism
        /// to restore execution from a given state, without executing other code to get there).
        ///
        /// From there, we don't want normal code flow:
        /// - from `yield return`, we'll jump to the enclosing `finally` (or method exit)
        /// - after finishing a `finally`, we'll jump to the next enclosing `finally` (or method exit)
        ///
        /// Some `finally` clauses may have already been rewritten and extracted to a plain block (<see cref="AsyncExceptionHandlerRewriter"/>).
        /// In those cases, we saved the finally-entry label in <see cref="BoundTryStatement.FinallyLabelOpt"/>.
        /// </summary>
        public override BoundNode VisitTryStatement(BoundTryStatement node)
        {
            _previousDisposalLabels ??= new ArrayBuilder <LabelSymbol>();
            _previousDisposalLabels.Push(_enclosingFinallyEntryOrFinallyExitOrExitLabel);

            var finallyExit = F.GenerateLabel("finallyExit");

            _previousDisposalLabels.Push(finallyExit);

            if (node.FinallyBlockOpt != null)
            {
                var finallyEntry = F.GenerateLabel("finallyEntry");
                _enclosingFinallyEntryOrFinallyExitOrExitLabel = finallyEntry;

                // Add finallyEntry label:
                //  try
                //  {
                //      ...
                //      finallyEntry:

                // Add finallyExit label:
                //  finally
                //  {
                //      ...
                //      finallyExit:
                //  }
                node = node.Update(
                    tryBlock: F.Block(node.TryBlock, F.Label(finallyEntry)),
                    node.CatchBlocks, F.Block(node.FinallyBlockOpt, F.Label(finallyExit)), node.FinallyLabelOpt, node.PreferFaultHandler);
            }
            else if ((object)node.FinallyLabelOpt != null)
            {
                _enclosingFinallyEntryOrFinallyExitOrExitLabel = node.FinallyLabelOpt;
            }

            var result = (BoundStatement)base.VisitTryStatement(node);

            // While inside the try and catch blocks, we'll use the current finallyEntry label for disposal
            // As soon as we close the try and catch blocks (ie. possibly enter the finally block), we'll use the finallyExit label for disposal (restored/popped from the stack by CloseTryCatchBlocks)
            Debug.Assert(_enclosingFinallyEntryOrFinallyExitOrExitLabel == finallyExit);

            // When exiting the try statement, we restore the previous disposal label.
            _enclosingFinallyEntryOrFinallyExitOrExitLabel = _previousDisposalLabels.Pop();

            if (node.FinallyBlockOpt != null)
            {
                // Append:
                //  if (disposeMode) /* jump to parent's finally or exit */
                result = AppendJumpToCurrentFinallyOrExit(result);
            }

            // Note: we add this jump to extracted `finally` blocks as well, using `VisitExtractedFinallyBlock` below

            return(result);
        }
예제 #32
0
        protected override BoundBlock VisitFinally(BoundBlock finallyBlock)
        {
            // within a finally, continuing disposal doesn't require any jump
            var savedDisposalLabel = _currentDisposalLabel;

            _currentDisposalLabel = null;
            var result = base.VisitFinally(finallyBlock);

            _currentDisposalLabel = savedDisposalLabel;
            return(result);
        }
예제 #33
0
        internal static bool NeedsLabel(this LabelSymbol label, string name1, string name2)
        {
            var labelName = label.Name;

            if (labelName.StartsWith("<"))
            {
                labelName = labelName.Substring(1);
            }

            return(labelName.StartsWith(name1) || labelName.StartsWith(name2));
        }
 private void CollectLabel(LabelSymbol label)
 {
     if ((object)label != null)
     {
         var currentLabels = this.currentLabels;
         if (currentLabels == null)
         {
             this.currentLabels = currentLabels = new HashSet <LabelSymbol>();
         }
         currentLabels.Add(label);
     }
 }
예제 #35
0
        /// <summary>
        /// Return the flow analysis state associated with a label.
        /// </summary>
        /// <param name="label"></param>
        /// <returns></returns>
        FlowAnalysisLocalState?LabelState(LabelSymbol label)
        {
            FlowAnalysisLocalState?result;

            if (labels.TryGetValue(label, out result))
            {
                return(result);
            }

            result = FlowAnalysisLocalState.UnreachableState(nextVariableSlot);
            labels.Add(label, result);
            return(result);
        }
예제 #36
0
        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);
        }
예제 #37
0
            internal AsyncMethodToClassRewriter(
               MethodSymbol method,
               AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
               SyntheticBoundNodeFactory factory,
               FieldSymbol state,
               FieldSymbol builder,
               Dictionary<Symbol, CapturedSymbol> localProxies,
               DiagnosticBag diagnostics)
                : base(factory, state, localProxies, diagnostics)
            {
                this.method = method;
                this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
                this.asyncMethodBuilderField = builder;
                this.exprReturnLabel = factory.GenerateLabel("exprReturn");

                this.exprRetValue = method.IsGenericTaskReturningAsync()
                    ? factory.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, GeneratedNames.AsyncExprRetValueFieldName())
                    : null;

                this.dynamicFactory = new LoweredDynamicOperationFactory(factory);
            }
        internal AsyncMethodToStateMachineRewriter(
            MethodSymbol method,
            AsyncMethodBuilderMemberCollection asyncMethodBuilderMemberCollection,
            SyntheticBoundNodeFactory F,
            FieldSymbol state,
            FieldSymbol builder,
            IReadOnlySet<Symbol> variablesCaptured,
            IReadOnlyDictionary<Symbol, CapturedSymbolReplacement> nonReusableLocalProxies,
            DiagnosticBag diagnostics)
            : base(F, method, state, variablesCaptured, nonReusableLocalProxies, diagnostics, useFinalizerBookkeeping: false)
        {
            this.method = method;
            this.asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection;
            this.asyncMethodBuilderField = builder;
            this.exprReturnLabel = F.GenerateLabel("exprReturn");
            this.exitLabel = F.GenerateLabel("exitLabel");

            this.exprRetValue = method.IsGenericTaskReturningAsync(F.Compilation)
                ? F.SynthesizedLocal(asyncMethodBuilderMemberCollection.ResultType, kind: SynthesizedLocalKind.AsyncMethodReturnValue)
                : null;

            this.dynamicFactory = new LoweredDynamicOperationFactory(F);
        }
예제 #39
0
        private void EmitStringSwitchJumpTable(
            BoundSwitchStatement switchStatement,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel,
            LocalOrParameter key,
            SyntaxNode syntaxNode)
        {
            LocalDefinition keyHash = null;

            // Condition is necessary, but not sufficient (e.g. might be missing a special or well-known member).
            if (SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch(_module, switchCaseLabels.Length))
            {
                Debug.Assert(_module.SupportsPrivateImplClass);

                var privateImplClass = _module.GetPrivateImplClass(syntaxNode, _diagnostics);
                Cci.IReference stringHashMethodRef = privateImplClass.GetMethod(PrivateImplementationDetails.SynthesizedStringHashFunctionName);

                // Heuristics and well-known member availability determine the existence
                // of this helper.  Rather than reproduce that (language-specific) logic here,
                // we simply check for the information we really want - whether the helper is
                // available.
                if (stringHashMethodRef != null)
                {
                    // static uint ComputeStringHash(string s)
                    // pop 1 (s)
                    // push 1 (uint return value)
                    // stackAdjustment = (pushCount - popCount) = 0

                    _builder.EmitLoad(key);
                    _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0);
                    _builder.EmitToken(stringHashMethodRef, syntaxNode, _diagnostics);

                    var UInt32Type = _module.Compilation.GetSpecialType(SpecialType.System_UInt32);
                    keyHash = AllocateTemp(UInt32Type, syntaxNode);

                    _builder.EmitLocalStore(keyHash);
                }
            }

            Cci.IReference stringEqualityMethodRef = _module.Translate(switchStatement.StringEquality, syntaxNode, _diagnostics);

            Cci.IMethodReference stringLengthRef = null;
            var stringLengthMethod = _module.Compilation.GetSpecialTypeMember(SpecialMember.System_String__Length) as MethodSymbol;
            if (stringLengthMethod != null && !stringLengthMethod.HasUseSiteError)
            {
                stringLengthRef = _module.Translate(stringLengthMethod, syntaxNode, _diagnostics);
            }

            SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate =
                (keyArg, stringConstant, targetLabel) =>
                {
                    if (stringConstant == ConstantValue.Null)
                    {
                        // if (key == null)
                        //      goto targetLabel
                        _builder.EmitLoad(keyArg);
                        _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue);
                    }
                    else if (stringConstant.StringValue.Length == 0 && stringLengthRef != null)
                    {
                        // if (key != null && key.Length == 0)
                        //      goto targetLabel

                        object skipToNext = new object();
                        _builder.EmitLoad(keyArg);
                        _builder.EmitBranch(ILOpCode.Brfalse, skipToNext, ILOpCode.Brtrue);

                        _builder.EmitLoad(keyArg);
                        // Stack: key --> length
                        _builder.EmitOpCode(ILOpCode.Call, 0);
                        var diag = DiagnosticBag.GetInstance();
                        _builder.EmitToken(stringLengthRef, null, diag);
                        Debug.Assert(diag.IsEmptyWithoutResolution);
                        diag.Free();

                        _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue);
                        _builder.MarkLabel(skipToNext);
                    }
                    else
                    {
                        this.EmitStringCompareAndBranch(key, syntaxNode, stringConstant, targetLabel, stringEqualityMethodRef);
                    }
                };

            _builder.EmitStringSwitchJumpTable(
                caseLabels: switchCaseLabels,
                fallThroughLabel: fallThroughLabel,
                key: key,
                keyHash: keyHash,
                emitStringCondBranchDelegate: emitStringCondBranchDelegate,
                computeStringHashcodeDelegate: SynthesizedStringSwitchHashMethod.ComputeStringHash);

            if (keyHash != null)
            {
                FreeTemp(keyHash);
            }
        }
예제 #40
0
        private void EmitSwitchHeader(
            BoundSwitchStatement switchStatement,
            BoundExpression expression,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel)
        {
            Debug.Assert(expression.ConstantValue == null);
            Debug.Assert((object)expression.Type != null &&
                expression.Type.IsValidV6SwitchGoverningType());
            Debug.Assert(switchCaseLabels.Length > 0);

            Debug.Assert(switchCaseLabels != null);

            LocalDefinition temp = null;
            LocalOrParameter key;
            BoundSequence sequence = null;

            if (expression.Kind == BoundKind.Sequence)
            {
                sequence = (BoundSequence)expression;
                DefineLocals(sequence);
                EmitSideEffects(sequence);
                expression = sequence.Value;
            }

            if (expression.Kind == BoundKind.SequencePointExpression)
            {
                var sequencePointExpression = (BoundSequencePointExpression)expression;
                EmitSequencePoint(sequencePointExpression);
                expression = sequencePointExpression.Expression;
            }

            switch (expression.Kind)
            {
                case BoundKind.Local:
                    var local = ((BoundLocal)expression).LocalSymbol;
                    if (local.RefKind == RefKind.None && !IsStackLocal(local))
                    {
                        key = this.GetLocal(local);
                        break;
                    }
                    goto default;

                case BoundKind.Parameter:
                    var parameter = (BoundParameter)expression;
                    if (parameter.ParameterSymbol.RefKind == RefKind.None)
                    {
                        key = ParameterSlot(parameter);
                        break;
                    }
                    goto default;

                default:
                    EmitExpression(expression, true);
                    temp = AllocateTemp(expression.Type, expression.Syntax);
                    _builder.EmitLocalStore(temp);
                    key = temp;
                    break;
            }

            // Emit switch jump table            
            if (expression.Type.SpecialType != SpecialType.System_String)
            {
                _builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, key, expression.Type.EnumUnderlyingType().PrimitiveTypeCode);
            }
            else
            {
                this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, key, expression.Syntax);
            }

            if (temp != null)
            {
                FreeTemp(temp);
            }

            if (sequence != null)
            {
                FreeLocals(sequence, doNotRelease: null);
            }
        }
            // returns a proxy for a label if branch must be hijacked to run finally
            // otherwise returns same label back
            public LabelSymbol ProxyLabelIfNeeded(LabelSymbol label)
            {
                // no need to proxy a label in the current frame or when we are at the root
                if (this.IsRoot() || (labels != null && labels.Contains(label)))
                {
                    return label;
                }

                var proxyLabels = this.proxyLabels;
                if (proxyLabels == null)
                {
                    this.proxyLabels = proxyLabels = new Dictionary<LabelSymbol, LabelSymbol>();
                }

                LabelSymbol proxy;
                if (!proxyLabels.TryGetValue(label, out proxy))
                {
                    proxy = new GeneratedLabelSymbol("proxy" + label.Name);
                    proxyLabels.Add(label, proxy);
                }

                return proxy;
            }
예제 #42
0
 private void RecordLabel(LabelSymbol label)
 {
     DummyLocal dummy;
     if (_dummyVariables.TryGetValue(label, out dummy))
     {
         RecordVarRead(dummy);
     }
     else
     {
         // this is a backwards jump with nontrivial stack requirements.
         // just use empty.
         dummy = empty;
         _dummyVariables.Add(label, dummy);
         RecordVarRead(dummy);
     }
 }
 private void CollectLabel(LabelSymbol label)
 {
     if ((object)label != null)
     {
         var currentLabels = this.currentLabels;
         if (currentLabels == null)
         {
             this.currentLabels = currentLabels = new HashSet<LabelSymbol>();
         }
         currentLabels.Add(label);
     }
 }
예제 #44
0
 public BoundSwitchLabel(CSharpSyntaxNode syntax, LabelSymbol label, bool hasErrors = false)
     : this(syntax, label, expressionOpt: null, hasErrors: hasErrors)
 {
 }
예제 #45
0
        private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder sectionBinder, LabelSymbol label, DiagnosticBag diagnostics)
        {
            var switchGoverningType = SwitchGoverningType;
            BoundExpression boundLabelExpressionOpt = null;
            ConstantValue labelExpressionConstant = null;

            // Prevent cascading diagnostics
            bool hasErrors = node.HasErrors;

            switch (node.Kind())
            {
                case SyntaxKind.CaseSwitchLabel:
                    var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
                    // Bind the label case expression
                    boundLabelExpressionOpt = sectionBinder.BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue);
                    boundLabelExpressionOpt = ConvertCaseExpression(caseLabelSyntax, boundLabelExpressionOpt, sectionBinder, ref labelExpressionConstant, diagnostics);

                    // Check for bind errors
                    hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors;

                    // SPEC:    The constant expression of each case label must denote a value that
                    // SPEC:    is implicitly convertible (§6.1) to the governing type of the switch statement.
                    if (!hasErrors && labelExpressionConstant == null)
                    {
                        diagnostics.Add(ErrorCode.ERR_ConstantExpected, caseLabelSyntax.Value.Location);
                        hasErrors = true;
                    }

                    if (!hasErrors && (object)labelExpressionConstant != null && FindMatchingSwitchCaseLabel(labelExpressionConstant, caseLabelSyntax) != label)
                    {
                        diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, labelExpressionConstant?.GetValueToDisplay() ?? label.Name);
                        hasErrors = true;
                    }

                    // LabelSymbols for all the switch case labels are created by BuildLabels().
                    // Fetch the matching switch case label symbols
                    break;
                case SyntaxKind.CasePatternSwitchLabel:
                    if (!node.HasErrors)
                    {
                        // This should not occur, because it would have been a syntax error
                        throw ExceptionUtilities.UnexpectedValue(node.Kind());
                    }
                    break;
                case SyntaxKind.DefaultSwitchLabel:
                    if (GetDefaultLabel() != label)
                    {
                        diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name);
                        hasErrors = true;
                    }
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(node.Kind());
            }

            return new BoundSwitchLabel(
                syntax: node,
                label: label,
                expressionOpt: boundLabelExpressionOpt,
                constantValueOpt: labelExpressionConstant,
                hasErrors: hasErrors);
        }
예제 #46
0
        private BoundPatternSwitchLabel BindPatternSwitchSectionLabel(
            Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics)
        {
            switch (node.Kind())
            {
                case SyntaxKind.CaseSwitchLabel:
                    {
                        var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
                        bool wasExpression;
                        var pattern = sectionBinder.BindConstantPattern(
                            node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true);
                        bool hasErrors = pattern.HasErrors;
                        var constantValue = pattern.ConstantValue;
                        if (!hasErrors &&
                            (object)constantValue != null &&
                            pattern.Value.Type == SwitchGoverningType &&
                            this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label)
                        {
                            diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name);
                            hasErrors = true;
                        }

                        // Until we've determined whether or not the switch label is reachable, we assume it
                        // is. The caller updates isReachable after determining if the label is subsumed.
                        const bool isReachable = true;
                        return new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors);
                    }

                case SyntaxKind.DefaultSwitchLabel:
                    {
                        var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node;
                        var pattern = new BoundWildcardPattern(node);
                        bool hasErrors = pattern.HasErrors;
                        if (defaultLabel != null)
                        {
                            diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name);
                            hasErrors = true;
                        }

                        // We always treat the default label as reachable, even if the switch is complete.
                        const bool isReachable = true;

                        // Note that this is semantically last! The caller will place it in the decision tree
                        // in the final position.
                        defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors);
                        return defaultLabel;
                    }

                case SyntaxKind.CasePatternSwitchLabel:
                    {
                        var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
                        var pattern = sectionBinder.BindPattern(
                            matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true);
                        return new BoundPatternSwitchLabel(node, label, pattern,
                            matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null,
                            true, node.HasErrors);
                    }

                default:
                    throw ExceptionUtilities.UnexpectedValue(node);
            }
        }
        private BoundPatternSwitchLabel BindPatternSwitchSectionLabel(
            Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics)
        {
            switch (node.Kind())
            {
                case SyntaxKind.CaseSwitchLabel:
                    {
                        var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
                        bool wasExpression;
                        var pattern = sectionBinder.BindConstantPattern(
                            node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true);
                        bool hasErrors = pattern.HasErrors;
                        var constantValue = pattern.ConstantValue;
                        if (!hasErrors && (object)constantValue != null && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label)
                        {
                            diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name);
                            hasErrors = true;
                        }
                        return new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors);
                    }

                case SyntaxKind.DefaultSwitchLabel:
                    {
                        var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node;
                        var pattern = new BoundWildcardPattern(node);
                        bool hasErrors = pattern.HasErrors;
                        if (defaultLabel != null)
                        {
                            diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, "default");
                            hasErrors = true;
                        }

                        // Note that this is semantically last! The caller will place it in the decision tree
                        // in the final position.
                        defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors);
                        return defaultLabel;
                    }

                case SyntaxKind.CasePatternSwitchLabel:
                    {
                        var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
                        var pattern = sectionBinder.BindPattern(
                            matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true);
                        return new BoundPatternSwitchLabel(node, label, pattern,
                            matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, node.HasErrors);
                    }

                default:
                    throw ExceptionUtilities.UnexpectedValue(node);
            }
        }
        protected override BoundStatement GenerateReturn(bool finished)
        {
            BoundLiteral result = this.F.Literal(!finished);

            if (_tryNestingLevel == 0)
            {
                return F.Return(result);
            }
            else
            {
                if ((object)_exitLabel == null)
                {
                    _exitLabel = this.F.GenerateLabel("exitLabel");
                    _methodValue = F.SynthesizedLocal(result.Type);
                }

                var gotoExit = F.Goto(_exitLabel);

                if (finished)
                {
                    // since we are finished, we need to treat this as a potential Leave
                    gotoExit = (BoundGotoStatement)VisitGotoStatement(gotoExit);
                }

                return this.F.Block(
                     F.Assignment(this.F.Local(_methodValue), result),
                     gotoExit);
            }
        }
        private BoundBlock PendBranches(
            AwaitFinallyFrame frame,
            LocalSymbol pendingBranchVar,
            LabelSymbol finallyLabel)
        {
            var bodyStatements = ArrayBuilder<BoundStatement>.GetInstance();

            // handle proxy labels if have any
            var proxiedLabels = frame.proxiedLabels;
            var proxyLabels = frame.proxyLabels;

            // skip 0 - it means we took no explicit branches
            int i = 1;
            if (proxiedLabels != null)
            {
                for (int cnt = proxiedLabels.Count; i <= cnt; i++)
                {
                    var proxied = proxiedLabels[i - 1];
                    var proxy = proxyLabels[proxied];

                    PendBranch(bodyStatements, proxy, i, pendingBranchVar, finallyLabel);
                }
            }

            var returnProxy = frame.returnProxyLabel;
            if (returnProxy != null)
            {
                PendBranch(bodyStatements, returnProxy, i, pendingBranchVar, finallyLabel);
            }

            return _F.Block(bodyStatements.ToImmutableAndFree());
        }
예제 #50
0
            private GeneratedLabelSymbol GetLabelClone(LabelSymbol label)
            {
                var labelClones = _labelClones;
                if (labelClones == null)
                {
                    _labelClones = labelClones = new Dictionary<LabelSymbol, GeneratedLabelSymbol>();
                }

                GeneratedLabelSymbol clone;
                if (!labelClones.TryGetValue(label, out clone))
                {
                    clone = new GeneratedLabelSymbol("cloned_" + label.Name);
                    labelClones.Add(label, clone);
                }

                return clone;
            }
 public virtual void VisitLabel(LabelSymbol symbol)
 {
     DefaultVisit(symbol);
 }
예제 #52
0
        private void EmitSwitchHeader(
            BoundSwitchStatement switchStatement,
            BoundExpression expression,
            KeyValuePair<ConstantValue, object>[] switchCaseLabels,
            LabelSymbol fallThroughLabel)
        {
            Debug.Assert(expression.ConstantValue == null);
            Debug.Assert((object)expression.Type != null &&
                expression.Type.IsValidSwitchGoverningType());
            Debug.Assert(switchCaseLabels.Length > 0);

            Debug.Assert(switchCaseLabels != null);

            var exprType = expression.Type;
            LocalDefinition temp = null;

            // Emit switch jump table            
            if (expression.Type.SpecialType != SpecialType.System_String)
            {
                if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None)
                {
                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
                else if (expression.Kind == BoundKind.Parameter && ((BoundParameter)expression).ParameterSymbol.RefKind == RefKind.None)
                {
                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, ParameterSlot((BoundParameter)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
                else
                {
                    EmitExpression(expression, true);
                    temp = AllocateTemp(exprType, expression.Syntax);
                    builder.EmitLocalStore(temp);

                    builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, temp, exprType.EnumUnderlyingType().PrimitiveTypeCode);
                }
            }
            else
            {
                if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None)
                {
                    this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), expression.Syntax);
                }
                else
                {
                    EmitExpression(expression, true);
                    temp = AllocateTemp(exprType, expression.Syntax);
                    builder.EmitLocalStore(temp);

                    this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, temp, expression.Syntax);
                }
            }

            if (temp != null)
            {
                FreeTemp(temp);
            }
        }
예제 #53
0
 // called on branches and labels
 private void RecordBranch(LabelSymbol label)
 {
     DummyLocal dummy;
     if (_dummyVariables.TryGetValue(label, out dummy))
     {
         RecordVarRead(dummy);
     }
     else
     {
         // create a dummy and start tracing it
         dummy = new DummyLocal();
         _dummyVariables.Add(label, dummy);
         _locals.Add(dummy, new LocalDefUseInfo(StackDepth()));
         RecordVarWrite(dummy);
     }
 }
예제 #54
0
        private static KeyValuePair<ConstantValue, object>[] GetSwitchCaseLabels(ImmutableArray<BoundSwitchSection> sections, ref LabelSymbol fallThroughLabel)
        {
            var labelsBuilder = ArrayBuilder<KeyValuePair<ConstantValue, object>>.GetInstance();
            foreach (var section in sections)
            {
                foreach (BoundSwitchLabel boundLabel in section.BoundSwitchLabels)
                {
                    var label = (SourceLabelSymbol)boundLabel.Label;
                    if (label.IdentifierNodeOrToken.CSharpKind() == SyntaxKind.DefaultSwitchLabel)
                    {
                        fallThroughLabel = label;
                    }
                    else
                    {
                        Debug.Assert(label.SwitchCaseLabelConstant != null
                            && SwitchConstantValueHelper.IsValidSwitchCaseLabelConstant(label.SwitchCaseLabelConstant));

                        labelsBuilder.Add(new KeyValuePair<ConstantValue, object>(label.SwitchCaseLabelConstant, label));
                    }
                }
            }

            return labelsBuilder.ToArrayAndFree();
        }
예제 #55
0
        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());
        }
예제 #56
0
        private static KeyValuePair<ConstantValue, object>[] GetSwitchCaseLabels(ImmutableArray<BoundSwitchSection> sections, ref LabelSymbol fallThroughLabel)
        {
            var labelsBuilder = ArrayBuilder<KeyValuePair<ConstantValue, object>>.GetInstance();
            foreach (var section in sections)
            {
                foreach (BoundSwitchLabel boundLabel in section.SwitchLabels)
                {
                    var label = boundLabel.Label;
                    if (boundLabel.ConstantValueOpt == null)
                    {
                        fallThroughLabel = label;
                    }
                    else
                    {
                        var value = boundLabel.ConstantValueOpt;
                        Debug.Assert(value != null
                            && SwitchConstantValueHelper.IsValidSwitchCaseLabelConstant(value));
                        labelsBuilder.Add(new KeyValuePair<ConstantValue, object>(value, label));
                    }
                }
            }

            return labelsBuilder.ToArrayAndFree();
        }
예제 #57
0
        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);
        }
예제 #58
0
 private void EmitConstantSwitchHeader(BoundExpression expression, LabelSymbol target)
 {
     EmitExpression(expression, false);
     _builder.EmitBranch(ILOpCode.Br, target);
 }
예제 #59
0
 public BoundLabelStatement Label(LabelSymbol label)
 {
     return new BoundLabelStatement(Syntax, label) { WasCompilerGenerated = true };
 }
        private void PendBranch(
            ArrayBuilder<BoundStatement> bodyStatements,
            LabelSymbol proxy,
            int i,
            LocalSymbol pendingBranchVar,
            LabelSymbol finallyLabel)
        {
            // branch lands here
            bodyStatements.Add(_F.Label(proxy));

            // pend the branch
            bodyStatements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Literal(i)));

            // skip other proxies
            bodyStatements.Add(_F.Goto(finallyLabel));
        }