private BoundExpression LowerSwitchExpression(BoundConvertedSwitchExpression node) { // When compiling for Debug (not Release), we produce the most detailed sequence points. var produceDetailedSequencePoints = GenerateInstrumentation && _localRewriter._compilation.Options.OptimizationLevel != OptimizationLevel.Release; _factory.Syntax = node.Syntax; var result = ArrayBuilder <BoundStatement> .GetInstance(); var outerVariables = ArrayBuilder <LocalSymbol> .GetInstance(); var loweredSwitchGoverningExpression = _localRewriter.VisitExpression(node.Expression); BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput( node.DecisionDag, loweredSwitchGoverningExpression, result, out BoundExpression savedInputExpression); Debug.Assert(savedInputExpression != null); object restorePointForEnclosingStatement = new object(); object restorePointForSwitchBody = new object(); // lower the decision dag. (ImmutableArray <BoundStatement> loweredDag, ImmutableDictionary <SyntaxNode, ImmutableArray <BoundStatement> > switchSections) = LowerDecisionDag(decisionDag); if (_whenNodeIdentifierLocal is not null) { outerVariables.Add(_whenNodeIdentifierLocal); } if (produceDetailedSequencePoints) { var syntax = (SwitchExpressionSyntax)node.Syntax; result.Add(new BoundSavePreviousSequencePoint(syntax, restorePointForEnclosingStatement)); // While evaluating the state machine, we highlight the `switch {...}` part. var spanStart = syntax.SwitchKeyword.Span.Start; var spanEnd = syntax.Span.End; var spanForSwitchBody = new TextSpan(spanStart, spanEnd - spanStart); result.Add(new BoundStepThroughSequencePoint(node.Syntax, span: spanForSwitchBody)); result.Add(new BoundSavePreviousSequencePoint(syntax, restorePointForSwitchBody)); } // add the rest of the lowered dag that references that input result.Add(_factory.Block(loweredDag)); // A branch to the default label when no switch case matches is included in the // decision tree, so the code in result is unreachable at this point. // Lower each switch expression arm LocalSymbol resultTemp = _factory.SynthesizedLocal(node.Type, node.Syntax, kind: SynthesizedLocalKind.LoweringTemp); LabelSymbol afterSwitchExpression = _factory.GenerateLabel("afterSwitchExpression"); foreach (BoundSwitchExpressionArm arm in node.SwitchArms) { _factory.Syntax = arm.Syntax; var sectionBuilder = ArrayBuilder <BoundStatement> .GetInstance(); sectionBuilder.AddRange(switchSections[arm.Syntax]); sectionBuilder.Add(_factory.Label(arm.Label)); var loweredValue = _localRewriter.VisitExpression(arm.Value); if (GenerateInstrumentation) { loweredValue = this._localRewriter._instrumenter.InstrumentSwitchExpressionArmExpression(arm.Value, loweredValue, _factory); } sectionBuilder.Add(_factory.Assignment(_factory.Local(resultTemp), loweredValue)); sectionBuilder.Add(_factory.Goto(afterSwitchExpression)); var statements = sectionBuilder.ToImmutableAndFree(); if (arm.Locals.IsEmpty) { result.Add(_factory.StatementList(statements)); } else { // Lifetime of these locals is expanded to the entire switch body, as it is possible to // share them as temps in the decision dag. outerVariables.AddRange(arm.Locals); // Note the language scope of the locals, even though they are included for the purposes of // lifetime analysis in the enclosing scope. result.Add(new BoundScope(arm.Syntax, arm.Locals, statements)); } } _factory.Syntax = node.Syntax; if (node.DefaultLabel != null) { result.Add(_factory.Label(node.DefaultLabel)); if (produceDetailedSequencePoints) { result.Add(new BoundRestorePreviousSequencePoint(node.Syntax, restorePointForSwitchBody)); } var objectType = _factory.SpecialType(SpecialType.System_Object); var thrownExpression = (implicitConversionExists(savedInputExpression, objectType) && _factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctorObject, isOptional: true) is MethodSymbol exception1) ? _factory.New(exception1, _factory.Convert(objectType, savedInputExpression)) : (_factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctor, isOptional: true) is MethodSymbol exception0) ? _factory.New(exception0) : _factory.New(_factory.WellKnownMethod(WellKnownMember.System_InvalidOperationException__ctor)); result.Add(_factory.Throw(thrownExpression)); } if (GenerateInstrumentation) { result.Add(_factory.HiddenSequencePoint()); } result.Add(_factory.Label(afterSwitchExpression)); if (produceDetailedSequencePoints) { result.Add(new BoundRestorePreviousSequencePoint(node.Syntax, restorePointForEnclosingStatement)); } outerVariables.Add(resultTemp); outerVariables.AddRange(_tempAllocator.AllTemps()); return(_factory.SpillSequence(outerVariables.ToImmutableAndFree(), result.ToImmutableAndFree(), _factory.Local(resultTemp))); bool implicitConversionExists(BoundExpression expression, TypeSymbol type) { var discardedUseSiteInfo = CompoundUseSiteInfo <AssemblySymbol> .Discarded; Conversion c = _localRewriter._compilation.Conversions.ClassifyConversionFromExpression(expression, type, ref discardedUseSiteInfo); return(c.IsImplicit); } }
private SwitchExpressionLocalRewriter(BoundConvertedSwitchExpression node, LocalRewriter localRewriter) : base(node.Syntax, localRewriter, node.SwitchArms.SelectAsArray(arm => arm.Syntax), generateInstrumentation: !node.WasCompilerGenerated && localRewriter.Instrument) { }
private BoundExpression LowerSwitchExpression(BoundConvertedSwitchExpression node) { _factory.Syntax = node.Syntax; var result = ArrayBuilder <BoundStatement> .GetInstance(); var outerVariables = ArrayBuilder <LocalSymbol> .GetInstance(); var loweredSwitchGoverningExpression = _localRewriter.VisitExpression(node.Expression); BoundDecisionDag decisionDag = ShareTempsIfPossibleAndEvaluateInput( node.DecisionDag, loweredSwitchGoverningExpression, result, out BoundExpression savedInputExpression); Debug.Assert(savedInputExpression != null); // lower the decision dag. (ImmutableArray <BoundStatement> loweredDag, ImmutableDictionary <SyntaxNode, ImmutableArray <BoundStatement> > switchSections) = LowerDecisionDag(decisionDag); // then add the rest of the lowered dag that references that input result.Add(_factory.Block(loweredDag)); // A branch to the default label when no switch case matches is included in the // decision tree, so the code in result is unreachable at this point. // Lower each switch expression arm LocalSymbol resultTemp = _factory.SynthesizedLocal(node.Type, node.Syntax, kind: SynthesizedLocalKind.LoweringTemp); LabelSymbol afterSwitchExpression = _factory.GenerateLabel("afterSwitchExpression"); foreach (BoundSwitchExpressionArm arm in node.SwitchArms) { _factory.Syntax = arm.Syntax; var sectionBuilder = ArrayBuilder <BoundStatement> .GetInstance(); sectionBuilder.AddRange(switchSections[arm.Syntax]); sectionBuilder.Add(_factory.Label(arm.Label)); sectionBuilder.Add(_factory.Assignment(_factory.Local(resultTemp), _localRewriter.VisitExpression(arm.Value))); sectionBuilder.Add(_factory.Goto(afterSwitchExpression)); var statements = sectionBuilder.ToImmutableAndFree(); if (arm.Locals.IsEmpty) { result.Add(_factory.StatementList(statements)); } else { // Lifetime of these locals is expanded to the entire switch body, as it is possible to // share them as temps in the decision dag. outerVariables.AddRange(arm.Locals); // Note the language scope of the locals, even though they are included for the purposes of // lifetime analysis in the enclosing scope. result.Add(new BoundScope(arm.Syntax, arm.Locals, statements)); } } _factory.Syntax = node.Syntax; if (node.DefaultLabel != null) { result.Add(_factory.Label(node.DefaultLabel)); var objectType = _factory.SpecialType(SpecialType.System_Object); var thrownExpression = (implicitConversionExists(savedInputExpression, objectType) && _factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctorObject, isOptional: true) is MethodSymbol exception1) ? _factory.New(exception1, _factory.Convert(objectType, savedInputExpression)) : (_factory.WellKnownMember(WellKnownMember.System_Runtime_CompilerServices_SwitchExpressionException__ctor, isOptional: true) is MethodSymbol exception0) ? _factory.New(exception0) : _factory.New(_factory.WellKnownMethod(WellKnownMember.System_InvalidOperationException__ctor)); result.Add(_factory.Throw(thrownExpression)); } result.Add(_factory.Label(afterSwitchExpression)); outerVariables.Add(resultTemp); outerVariables.AddRange(_tempAllocator.AllTemps()); return(_factory.SpillSequence(outerVariables.ToImmutableAndFree(), result.ToImmutableAndFree(), _factory.Local(resultTemp))); bool implicitConversionExists(BoundExpression expression, TypeSymbol type) { HashSet <DiagnosticInfo> discarded = null; Conversion c = _localRewriter._compilation.Conversions.ClassifyConversionFromExpression(expression, type, ref discarded); return(c.IsImplicit); } }
public override BoundNode VisitConvertedSwitchExpression(BoundConvertedSwitchExpression node) { return(this.VisitSwitchExpression(node)); }
private SwitchExpressionLocalRewriter(BoundConvertedSwitchExpression node, LocalRewriter localRewriter) : base(node.Syntax, localRewriter, node.SwitchArms.SelectAsArray(arm => arm.Syntax)) { }