private bool FullyHandlesItsInput(BoundPatternSwitchStatement node) { // If the switch is complete (for example, because it has a default label), // just return true. if (node.IsComplete) { return(true); } // We also check for completeness based on value. Other cases were handled in the construction of the decision tree. if (node.Expression.ConstantValue == null) { return(false); } foreach (var section in node.SwitchSections) { foreach (var label in section.SwitchLabels) { if (label.Guard != null && label.Guard.ConstantValue != ConstantValue.True) { continue; } if (label.Pattern.Kind == BoundKind.ConstantPattern && ((BoundConstantPattern)label.Pattern).ConstantValue == node.Expression.ConstantValue) { return(true); } } } return(false); }
private void VisitPatternSwitchBlock(BoundPatternSwitchStatement node) { var afterSwitchState = UnreachableState(); var switchSections = node.SwitchSections; var iLastSection = (switchSections.Length - 1); // simulate the dispatch (setting pattern variables and jumping to labels) using the decision tree VisitDecisionTree(node.DecisionTree); // we always consider the default label reachable for flow analysis purposes. if (node.DefaultLabel != null) { _pendingBranches.Add(new PendingBranch(node.DefaultLabel, this.State)); } // visit switch sections for (var iSection = 0; iSection <= iLastSection; iSection++) { VisitPatternSwitchSection(switchSections[iSection], node.Expression, 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); }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { // The pattern switch statement has computed a state machine, and gathered diagnostics // related to subsumption. We report those here. Diagnostics.AddRange(node.DecisionTreeDiagnostics); return(base.VisitPatternSwitchStatement(node)); }
public PatternSwitchLocalRewriter(LocalRewriter localRewriter, BoundPatternSwitchStatement node) { this.LocalRewriter = localRewriter; this._factory = localRewriter._factory; foreach (var section in node.SwitchSections) { SwitchSections.Add(section, ArrayBuilder<BoundStatement>.GetInstance()); } }
private void VisitPatternSwitchBlock(BoundPatternSwitchStatement node) { var initialState = this.State; var afterSwitchState = UnreachableState(); var switchSections = node.SwitchSections; var iLastSection = (switchSections.Length - 1); // simulate the dispatch (setting pattern variables and jumping to labels) to // all reachable switch labels foreach (var section in switchSections) { foreach (var label in section.SwitchLabels) { if (label.IsReachable && label != node.DefaultLabel) { SetState(initialState.Clone()); // assign pattern variables VisitPattern(null, label.Pattern); SetState(StateWhenTrue); if (label.Guard != null) { VisitCondition(label.Guard); SetState(StateWhenTrue); } _pendingBranches.Add(new PendingBranch(label, this.State)); } } } // we always consider the default label reachable for flow analysis purposes // unless there was a single case that would match every input. if (node.DefaultLabel != null) { if (node.SomeLabelAlwaysMatches) { SetUnreachable(); } else { SetState(initialState.Clone()); } _pendingBranches.Add(new PendingBranch(node.DefaultLabel, this.State)); } // visit switch sections for (var iSection = 0; iSection <= iLastSection; iSection++) { VisitPatternSwitchSection(switchSections[iSection], node.Expression, 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); }
public PatternSwitchLocalRewriter(LocalRewriter localRewriter, BoundPatternSwitchStatement node) { this.LocalRewriter = localRewriter; this._factory = localRewriter._factory; foreach (var section in node.SwitchSections) { SwitchSections.Add(section, ArrayBuilder <BoundStatement> .GetInstance()); } }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { _factory.Syntax = node.Syntax; var pslr = new PatternSwitchLocalRewriter(this, node); var expression = VisitExpression(node.Expression); // 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) { expression = _instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory); } var result = ArrayBuilder <BoundStatement> .GetInstance(); // output the decision tree part pslr.LowerDecisionTree(expression, node.DecisionTree, result); // if the endpoint is reachable, we exit the switch if (!node.DecisionTree.MatchIsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionBuilder = pslr.SwitchSections[section]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); BoundStatement translatedSwitch = _factory.Block(pslr.DeclaredTemps.ToImmutableArray().Concat(node.InnerLocals), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (!node.WasCompilerGenerated && this.Instrument) { translatedSwitch = _instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch); } return(translatedSwitch); }
// 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())); }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { // visit switch header LocalState breakState = VisitPatternSwitchHeader(node); // visit switch block VisitPatternSwitchBlock(node); IntersectWith(ref breakState, ref this.State); ResolveBreaks(breakState, node.BreakLabel); return(null); }
public DecisionTreeComputer( Symbol enclosingSymbol, DiagnosticBag diagnostics, BoundPatternSwitchStatement switchStatement, Conversions conversions) { this._enclosingSymbol = enclosingSymbol; this._diagnostics = diagnostics; this._switchStatement = switchStatement; this._conversions = conversions; }
private PatternSwitchLocalRewriter(LocalRewriter localRewriter, BoundPatternSwitchStatement node) : base(localRewriter._factory.CurrentMethod, (SwitchStatementSyntax)node.Syntax, localRewriter._factory.Compilation.Conversions) { this._localRewriter = localRewriter; this._factory = localRewriter._factory; this._factory.Syntax = node.Syntax; foreach (var section in node.SwitchSections) { _switchSections.Add(section.Syntax, ArrayBuilder <BoundStatement> .GetInstance()); } }
// 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()); }
private PatternSwitchLocalRewriter(LocalRewriter localRewriter, BoundPatternSwitchStatement node) : base(localRewriter._factory.CurrentMethod, localRewriter._factory.Compilation.Conversions) { this._localRewriter = localRewriter; this._factory = localRewriter._factory; this._factory.Syntax = node.Syntax; foreach (var section in node.SwitchSections) { _switchSections.Add((SyntaxNode)section.Syntax, ArrayBuilder<BoundStatement>.GetInstance()); } }
public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement 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.InstrumentPatternSwitchStatement(original, rewritten), span: switchSequencePointSpan, hasErrors: false)); }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { _factory.Syntax = node.Syntax; var pslr = new PatternSwitchLocalRewriter(this, node); var expression = VisitExpression(node.Expression); var result = ArrayBuilder<BoundStatement>.GetInstance(); // output the decision tree part pslr.LowerDecisionTree(expression, node.DecisionTree, result); // if the endpoint is reachable, we exit the switch if (!node.DecisionTree.MatchIsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionBuilder = pslr.SwitchSections[section]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); BoundStatement translatedSwitch = _factory.Block(pslr.DeclaredTemps.ToImmutableArray().Concat(node.InnerLocals), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Create the sequence point if generating debug info and // node is not compiler generated if (this.Instrument && !node.WasCompilerGenerated) { translatedSwitch = _instrumenter.InstrumentBoundPatternSwitchStatement(node, translatedSwitch); } return translatedSwitch; }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { _factory.Syntax = node.Syntax; var pslr = new PatternSwitchLocalRewriter(this, node); var expression = VisitExpression(node.Expression); var result = ArrayBuilder <BoundStatement> .GetInstance(); // output the decision tree part pslr.LowerDecisionTree(expression, node.DecisionTree, result); // if the endpoint is reachable, we exit the switch if (!node.DecisionTree.MatchIsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionBuilder = pslr.SwitchSections[section]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); BoundStatement translatedSwitch = _factory.Block(pslr.DeclaredTemps.ToImmutableArray().Concat(node.InnerLocals), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Create the sequence point if generating debug info and // node is not compiler generated if (this.Instrument && !node.WasCompilerGenerated) { translatedSwitch = _instrumenter.InstrumentBoundPatternSwitchStatement(node, translatedSwitch); } return(translatedSwitch); }
/// <summary> /// Visit the switch expression, and return the initial break state. /// </summary> private LocalState VisitPatternSwitchHeader(BoundPatternSwitchStatement node) { // visit switch expression VisitRvalue(node.Expression); // return the exit state to use if no pattern matches if (FullyHandlesItsInput(node.DecisionTree)) { return(UnreachableState()); } else { return(this.State); } }
private void VisitPatternSwitchBlock(BoundPatternSwitchStatement node) { var afterSwitchState = UnreachableState(); var switchSections = node.PatternSwitchSections; var iLastSection = (switchSections.Length - 1); var dispatchState = this.State.Clone(); // visit switch sections for (var iSection = 0; iSection <= iLastSection; iSection++) { SetState(dispatchState.Clone()); VisitPatternSwitchSection(switchSections[iSection], node.Expression, 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); }
private DecisionTree LowerToDecisionTree( BoundExpression loweredExpression, BoundPatternSwitchStatement node) { var loweredDecisionTree = DecisionTree.Create(loweredExpression, loweredExpression.Type, _enclosingSymbol); BoundPatternSwitchLabel defaultLabel = null; SyntaxNode defaultSection = null; foreach (var section in node.SwitchSections) { var sectionSyntax = (SyntaxNode)section.Syntax; foreach (var label in section.SwitchLabels) { var loweredLabel = LowerSwitchLabel(label); if (loweredLabel.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel) { if (defaultLabel != null) { // duplicate switch label will have been reported during initial binding. } else { defaultLabel = loweredLabel; defaultSection = sectionSyntax; } } else { Syntax = label.Syntax; AddToDecisionTree(loweredDecisionTree, sectionSyntax, loweredLabel); } } } if (defaultLabel != null) { Add(loweredDecisionTree, (e, t) => new DecisionTree.Guarded(loweredExpression, loweredExpression.Type, default(ImmutableArray <KeyValuePair <BoundExpression, BoundExpression> >), defaultSection, null, defaultLabel)); } // We discard use-site diagnostics, as they have been reported during initial binding. _useSiteDiagnostics.Clear(); return(loweredDecisionTree); }
private DecisionTree LowerToDecisionTree( BoundExpression loweredExpression, BoundPatternSwitchStatement node) { var loweredDecisionTree = CreateEmptyDecisionTree(loweredExpression); BoundPatternSwitchLabel defaultLabel = null; SyntaxNode defaultSection = null; foreach (var section in node.SwitchSections) { var sectionSyntax = section.Syntax; foreach (var label in section.SwitchLabels) { var loweredLabel = LowerSwitchLabel(label); if (loweredLabel.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel) { if (defaultLabel != null) { // duplicate switch label will have been reported during initial binding. } else { defaultLabel = loweredLabel; defaultSection = sectionSyntax; } } else { AddToDecisionTree(loweredDecisionTree, sectionSyntax, loweredLabel); } } } if (defaultLabel != null && !loweredDecisionTree.MatchIsComplete) { Add(loweredDecisionTree, (e, t) => new DecisionTree.Guarded( expression: loweredExpression, type: loweredExpression.Type, bindings: default,
/// <summary> /// Visit the switch expression, and return the initial break state. /// </summary> private LocalState VisitPatternSwitchHeader(BoundPatternSwitchStatement node) { // decide if the switch has the moral equivalent of a default label. bool hasDefaultLabel = false; foreach (var section in node.PatternSwitchSections) { foreach (var boundPatternSwitchLabel in section.PatternSwitchLabels) { if (boundPatternSwitchLabel.Guard != null && !IsConstantTrue(boundPatternSwitchLabel.Guard)) { continue; } if (boundPatternSwitchLabel.Pattern.Kind == BoundKind.WildcardPattern || boundPatternSwitchLabel.Pattern.Kind == BoundKind.DeclarationPattern && ((BoundDeclarationPattern)boundPatternSwitchLabel.Pattern).IsVar) { hasDefaultLabel = true; goto foundDefaultLabel; } } } foundDefaultLabel :; // visit switch expression VisitRvalue(node.Expression); // return the state to use if no pattern matches if (hasDefaultLabel) { return(UnreachableState()); } else { return(this.State); } }
public override BoundStatement InstrumentBoundPatternSwitchStatement(BoundPatternSwitchStatement 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.InstrumentBoundPatternSwitchStatement(original, rewritten), span: switchSequencePointSpan, hasErrors: false); }
private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node) { var expression = _localRewriter.VisitExpression(node.Expression); var result = ArrayBuilder <BoundStatement> .GetInstance(); // 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 && _localRewriter.Instrument) { var instrumentedExpression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory); if (expression.ConstantValue == null) { expression = instrumentedExpression; } else { // If the expression is a constant, we leave it alone (the decision tree lowering code needs // to see that constant). But we add an additional leading statement with the instrumented expression. result.Add(_factory.ExpressionStatement(instrumentedExpression)); } } // output the decision tree part LowerPatternSwitch(expression, node, result); // if the endpoint is reachable, we exit the switch if (!node.IsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. _declaredTemps.AddRange(node.InnerLocals); // output the sections of code foreach (var section in node.SwitchSections) { // Lifetime of these locals is expanded to the entire switch body. _declaredTemps.AddRange(section.Locals); // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionSyntax = (SyntaxNode)section.Syntax; var sectionBuilder = _switchSections[sectionSyntax]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); ImmutableArray <BoundStatement> statements = sectionBuilder.ToImmutableAndFree(); if (section.Locals.IsEmpty) { result.Add(_factory.StatementList(statements)); } else { result.Add(new BoundScope(section.Syntax, section.Locals, statements)); } // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); BoundStatement translatedSwitch = _factory.Block(_declaredTemps.ToImmutableArray(), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (!node.WasCompilerGenerated && _localRewriter.Instrument) { translatedSwitch = _localRewriter._instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch); } return(translatedSwitch); }
internal static BoundStatement MakeLoweredForm(LocalRewriter localRewriter, BoundPatternSwitchStatement node) { return(new PatternSwitchLocalRewriter(localRewriter, node).MakeLoweredForm(node)); }
public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { return AddDynamicAnalysis(original, base.InstrumentPatternSwitchStatement(original, rewritten)); }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { return PatternSwitchLocalRewriter.MakeLoweredForm(this, node); }
private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node) { var expression = _localRewriter.VisitExpression(node.Expression); var result = ArrayBuilder <BoundStatement> .GetInstance(); // if the expression is "too complex", we copy it to a temp. LocalSymbol initialTemp = null; if (expression.ConstantValue == null) { initialTemp = _factory.SynthesizedLocal(expression.Type, expression.Syntax); result.Add(_factory.Assignment(_factory.Local(initialTemp), expression)); expression = _factory.Local(initialTemp); } // 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 && _localRewriter.Instrument) { expression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory); } // output the decision tree part LowerPatternSwitch(expression, node, result); // if the endpoint is reachable, we exit the switch if (!node.IsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionSyntax = (SyntaxNode)section.Syntax; var sectionBuilder = _switchSections[sectionSyntax]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); _declaredTemps.AddOptional(initialTemp); _declaredTemps.AddRange(node.InnerLocals); BoundStatement translatedSwitch = _factory.Block(_declaredTemps.ToImmutableArray(), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (!node.WasCompilerGenerated && _localRewriter.Instrument) { translatedSwitch = _localRewriter._instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch); } return(translatedSwitch); }
public virtual BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement); return(InstrumentStatement(original, rewritten)); }
/// <summary> /// Lower the given pattern switch statement into a decision tree and then to a sequence of statements into the given statement builder. /// </summary> private void LowerPatternSwitch(BoundExpression loweredExpression, BoundPatternSwitchStatement node, ArrayBuilder<BoundStatement> loweredDecisionTree) { var decisionTree = LowerToDecisionTree(loweredExpression, node); LowerDecisionTree(loweredExpression, decisionTree, loweredDecisionTree); }
public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { return(AddDynamicAnalysis(original, base.InstrumentPatternSwitchStatement(original, rewritten))); }
public override BoundStatement InstrumentBoundPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { return Previous.InstrumentBoundPatternSwitchStatement(original, rewritten); }
private DecisionTree LowerToDecisionTree( BoundExpression loweredExpression, BoundPatternSwitchStatement node) { var loweredDecisionTree = DecisionTree.Create(loweredExpression, loweredExpression.Type, _enclosingSymbol); BoundPatternSwitchLabel defaultLabel = null; SyntaxNode defaultSection = null; foreach (var section in node.SwitchSections) { var sectionSyntax = (SyntaxNode)section.Syntax; foreach (var label in section.SwitchLabels) { var loweredLabel = LowerSwitchLabel(label); if (loweredLabel.Syntax.Kind() == SyntaxKind.DefaultSwitchLabel) { if (defaultLabel != null) { // duplicate switch label will have been reported during initial binding. } else { defaultLabel = loweredLabel; defaultSection = sectionSyntax; } } else { Syntax = label.Syntax; AddToDecisionTree(loweredDecisionTree, sectionSyntax, loweredLabel); } } } if (defaultLabel != null) { Add(loweredDecisionTree, (e, t) => new DecisionTree.Guarded(loweredExpression, loweredExpression.Type, default(ImmutableArray<KeyValuePair<BoundExpression, BoundExpression>>), defaultSection, null, defaultLabel)); } // We discard use-site diagnostics, as they have been reported during initial binding. _useSiteDiagnostics.Clear(); return loweredDecisionTree; }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { return(base.VisitPatternSwitchStatement(node)); }
/// <summary> /// Lower the given pattern switch statement into a decision tree and then to a sequence of statements into the given statement builder. /// </summary> private void LowerPatternSwitch(BoundExpression loweredExpression, BoundPatternSwitchStatement node, ArrayBuilder <BoundStatement> loweredDecisionTree) { var decisionTree = LowerToDecisionTree(loweredExpression, node); LowerDecisionTree(loweredExpression, decisionTree, loweredDecisionTree); }
public virtual BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { Debug.Assert(original.Syntax.Kind() == SyntaxKind.SwitchStatement); return InstrumentStatement(original, rewritten); }
public override BoundNode VisitPatternSwitchStatement(BoundPatternSwitchStatement node) { return(PatternSwitchLocalRewriter.MakeLoweredForm(this, node)); }
private BoundStatement MakeLoweredForm(BoundPatternSwitchStatement node) { var expression = _localRewriter.VisitExpression(node.Expression); var result = ArrayBuilder<BoundStatement>.GetInstance(); // if the expression is "too complex", we copy it to a temp. LocalSymbol initialTemp = null; if (expression.ConstantValue == null) { initialTemp = _factory.SynthesizedLocal(expression.Type, expression.Syntax); result.Add(_factory.Assignment(_factory.Local(initialTemp), expression)); expression = _factory.Local(initialTemp); } // 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 && _localRewriter.Instrument) { expression = _localRewriter._instrumenter.InstrumentSwitchStatementExpression(node, expression, _factory); } // output the decision tree part LowerPatternSwitch(expression, node, result); // if the endpoint is reachable, we exit the switch if (!node.IsComplete) { result.Add(_factory.Goto(node.BreakLabel)); } // at this point the end of result is unreachable. // output the sections of code foreach (var section in node.SwitchSections) { // Start with the part of the decision tree that is in scope of the section variables. // Its endpoint is not reachable (it jumps back into the decision tree code). var sectionSyntax = (SyntaxNode)section.Syntax; var sectionBuilder = _switchSections[sectionSyntax]; // Add labels corresponding to the labels of the switch section. foreach (var label in section.SwitchLabels) { sectionBuilder.Add(_factory.Label(label.Label)); } // Add the translated body of the switch section sectionBuilder.AddRange(_localRewriter.VisitList(section.Statements)); sectionBuilder.Add(_factory.Goto(node.BreakLabel)); result.Add(_factory.Block(section.Locals, sectionBuilder.ToImmutableAndFree())); // at this point the end of result is unreachable. } result.Add(_factory.Label(node.BreakLabel)); _declaredTemps.AddOptional(initialTemp); _declaredTemps.AddRange(node.InnerLocals); BoundStatement translatedSwitch = _factory.Block(_declaredTemps.ToImmutableArray(), node.InnerLocalFunctions, result.ToImmutableAndFree()); // Only add instrumentation (such as a sequence point) if the node is not compiler-generated. if (!node.WasCompilerGenerated && _localRewriter.Instrument) { translatedSwitch = _localRewriter._instrumenter.InstrumentPatternSwitchStatement(node, translatedSwitch); } return translatedSwitch; }
internal static BoundStatement MakeLoweredForm(LocalRewriter localRewriter, BoundPatternSwitchStatement node) { return new PatternSwitchLocalRewriter(localRewriter, node).MakeLoweredForm(node); }
public override BoundStatement InstrumentPatternSwitchStatement(BoundPatternSwitchStatement original, BoundStatement rewritten) { return(Previous.InstrumentPatternSwitchStatement(original, rewritten)); }