| File: Lowering\LocalRewriter\LocalRewriter_BasePatternSwitchLocalRewriter.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp { internal partial class LocalRewriter { /// <summary> /// A common base class for lowering the pattern switch statement and the pattern switch expression. /// </summary> private abstract class BaseSwitchLocalRewriter : DecisionDagRewriter { /// <summary> /// Map from when clause's syntax to the lowered code for the matched pattern. The code for a section /// includes the code to assign to the pattern variables and evaluate the when clause. Since a /// when clause can yield a false value, it can jump back to a label in the lowered decision dag. /// </summary> private readonly PooledDictionary<SyntaxNode, ArrayBuilder<BoundStatement>> _switchArms = PooledDictionary<SyntaxNode, ArrayBuilder<BoundStatement>>.GetInstance(); protected override ArrayBuilder<BoundStatement> BuilderForSection(SyntaxNode whenClauseSyntax) { // We need the section syntax to get the section builder from the map. Unfortunately this is a bit awkward SyntaxNode? sectionSyntax = whenClauseSyntax is SwitchLabelSyntax l ? l.Parent : whenClauseSyntax; Debug.Assert(sectionSyntax is { }); bool found = _switchArms.TryGetValue(sectionSyntax, out ArrayBuilder<BoundStatement>? result); if (!found || result == null) throw new InvalidOperationException(); return result; } protected BaseSwitchLocalRewriter( SyntaxNode node, LocalRewriter localRewriter, ImmutableArray<SyntaxNode> arms, bool generateInstrumentation) : base(node, localRewriter, generateInstrumentation) { foreach (var arm in arms) { var armBuilder = ArrayBuilder<BoundStatement>.GetInstance(); // We start each switch block of a switch statement with a hidden sequence point so that // we do not appear to be in the previous switch block when we begin. if (GenerateInstrumentation) armBuilder.Add(_factory.HiddenSequencePoint()); _switchArms.Add(arm, armBuilder); } } protected new void Free() { foreach (var entry in _switchArms) { entry.Value.Free(); } _switchArms.Free(); base.Free(); } /// <summary> /// Lower the given nodes into _loweredDecisionDag. Should only be called once per instance of this. /// </summary> protected (ImmutableArray<BoundStatement> loweredDag, ImmutableDictionary<SyntaxNode, ImmutableArray<BoundStatement>> switchSections) LowerDecisionDag(BoundDecisionDag decisionDag) { var loweredDag = LowerDecisionDagCore(decisionDag); var switchSections = _switchArms.ToImmutableDictionary(kv => kv.Key, kv => kv.Value.ToImmutableAndFree()); _switchArms.Clear(); return (loweredDag, switchSections); } } } }