public override BoundNode VisitLabeledStatement(BoundLabeledStatement node) { Debug.Assert(node != null); var rewrittenBody = (BoundStatement)Visit(node.Body); BoundStatement labelStatement = new BoundLabelStatement(node.Syntax, node.Label); if (this.GenerateDebugInfo) { var labeledSyntax = node.Syntax as LabeledStatementSyntax; if (labeledSyntax != null) { var span = TextSpan.FromBounds(labeledSyntax.Identifier.SpanStart, labeledSyntax.ColonToken.Span.End); labelStatement = factory.SequencePointWithSpan(labeledSyntax, span, labelStatement); } } if (rewrittenBody == null) { // Body may be null if the body has no associated IL // (declaration with no initializer for instance.) return(labelStatement); } return(BoundStatementList.Synthesized(node.Syntax, labelStatement, rewrittenBody)); }
public override BoundNode VisitLabeledStatement(BoundLabeledStatement node) { Debug.Assert(node != null); var rewrittenBody = (BoundStatement)Visit(node.Body); BoundStatement labelStatement = new BoundLabelStatement(node.Syntax, node.Label); if (this.GenerateDebugInfo) { var labeledSyntax = node.Syntax as LabeledStatementSyntax; if (labeledSyntax != null) { var span = TextSpan.FromBounds(labeledSyntax.Identifier.SpanStart, labeledSyntax.ColonToken.Span.End); labelStatement = _factory.SequencePointWithSpan(labeledSyntax, span, labelStatement); } } if (rewrittenBody == null) { // Body may be null if the body has no associated IL // (declaration with no initializer for instance.) return labelStatement; } return BoundStatementList.Synthesized(node.Syntax, labelStatement, rewrittenBody); }
public override BoundNode VisitLabeledStatement(BoundLabeledStatement node) { Debug.Assert(node != null); var rewrittenBody = (BoundStatement)Visit(node.Body); BoundStatement labelStatement = new BoundLabelStatement(node.Syntax, node.Label); if (this.Instrument) { var labeledSyntax = node.Syntax as LabeledStatementSyntax; if (labeledSyntax != null) { labelStatement = _instrumenter.InstrumentLabelStatement(node, labelStatement); } } if (rewrittenBody == null) { // Body may be null if the body has no associated IL // (declaration with no initializer for instance.) return labelStatement; } return BoundStatementList.Synthesized(node.Syntax, labelStatement, rewrittenBody); }
private BoundStatement MakeLabeledStatement( BoundLabeledStatement node, BoundStatement?rewrittenBody ) { BoundStatement labelStatement = new BoundLabelStatement(node.Syntax, node.Label); if (this.Instrument) { var labeledSyntax = node.Syntax as LabeledStatementSyntax; if (labeledSyntax != null) { labelStatement = _instrumenter.InstrumentLabelStatement(node, labelStatement); } } if (rewrittenBody == null) { // Body may be null if the body has no associated IL // (declaration with no initializer for instance.) return(labelStatement); } return(BoundStatementList.Synthesized(node.Syntax, labelStatement, rewrittenBody)); }
public override BoundNode VisitLabeledStatement(BoundLabeledStatement node) { Debug.Assert(node != null); var rewrittenBody = (BoundStatement)Visit(node.Body); BoundStatement labelStatement = new BoundLabelStatement(node.Syntax, node.Label); if (this.Instrument) { var labeledSyntax = node.Syntax as LabeledStatementSyntax; if (labeledSyntax != null) { labelStatement = _instrumenter.InstrumentLabelStatement(node, labelStatement); } } if (rewrittenBody == null) { // Body may be null if the body has no associated IL // (declaration with no initializer for instance.) return(labelStatement); } return(BoundStatementList.Synthesized(node.Syntax, labelStatement, rewrittenBody)); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { if (IsInside) { _labelsInside.Add(node.Label); } return(base.VisitLabelStatement(node)); }
private BoundStatement RewriteWhileStatement( BoundWhileStatement loop, ImmutableArray <LocalSymbol> locals, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { if (locals.IsEmpty) { return(RewriteWhileStatement(loop, rewrittenCondition, rewrittenBody, breakLabel, continueLabel, hasErrors)); } // We need to enter scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // while (condition) // body; // // becomes // // continue: // { // GotoIfFalse condition break; // body // goto continue; // } // break: SyntaxNode syntax = loop.Syntax; BoundStatement continueLabelStatement = new BoundLabelStatement(syntax, continueLabel); BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, breakLabel); if (this.Instrument && !loop.WasCompilerGenerated) { ifNotConditionGotoBreak = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak(loop, ifNotConditionGotoBreak); continueLabelStatement = new BoundSequencePoint(null, continueLabelStatement); } return(BoundStatementList.Synthesized(syntax, hasErrors, continueLabelStatement, new BoundBlock(syntax, locals, ImmutableArray.Create( ifNotConditionGotoBreak, rewrittenBody, new BoundGotoStatement(syntax, continueLabel))), new BoundLabelStatement(syntax, breakLabel))); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { CollectLabel(node.Label); return base.VisitLabelStatement(node); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { if (IsInside) _labelsInside.Add(node.Label); return base.VisitLabelStatement(node); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { AddTarget(node.Label); return(base.VisitLabelStatement(node)); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { CollectLabel(node.Label); return(base.VisitLabelStatement(node)); }
private BoundStatement RewriteForStatement( BoundForStatement node, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody) { if (node.InnerLocals.IsEmpty) { return RewriteForStatementWithoutInnerLocals( node, node.OuterLocals, rewrittenInitializer, rewrittenCondition, rewrittenIncrement, rewrittenBody, node.BreakLabel, node.ContinueLabel, node.HasErrors); } // We need to enter inner_scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // for (initializer; condition; increment) // body; // // becomes the following (with block added for locals) // // { // initializer; // start: // { // GotoIfFalse condition break; // body; // continue: // increment; // goto start; // } // break: // } Debug.Assert(rewrittenBody != null); SyntaxNode syntax = node.Syntax; var statementBuilder = ArrayBuilder<BoundStatement>.GetInstance(); // initializer; if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } var startLabel = new GeneratedLabelSymbol("start"); // start: BoundStatement startLabelStatement = new BoundLabelStatement(syntax, startLabel); if (Instrument) { startLabelStatement = new BoundSequencePoint(null, startLabelStatement); } statementBuilder.Add(startLabelStatement); var blockBuilder = ArrayBuilder<BoundStatement>.GetInstance(); // GotoIfFalse condition break; if (rewrittenCondition != null) { BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, node.BreakLabel); if (this.Instrument) { ifNotConditionGotoBreak = _instrumenter.InstrumentForStatementConditionalGotoStartOrBreak(node, ifNotConditionGotoBreak); } blockBuilder.Add(ifNotConditionGotoBreak); } // body; blockBuilder.Add(rewrittenBody); // continue: // increment; blockBuilder.Add(new BoundLabelStatement(syntax, node.ContinueLabel)); if (rewrittenIncrement != null) { blockBuilder.Add(rewrittenIncrement); } // goto start; blockBuilder.Add(new BoundGotoStatement(syntax, startLabel)); statementBuilder.Add(new BoundBlock(syntax, node.InnerLocals, blockBuilder.ToImmutableAndFree())); // break: statementBuilder.Add(new BoundLabelStatement(syntax, node.BreakLabel)); var statements = statementBuilder.ToImmutableAndFree(); return new BoundBlock(syntax, node.OuterLocals, statements, node.HasErrors); }
public override BoundNode VisitLabelStatement(BoundLabelStatement node) { AddTarget(node.Label); return base.VisitLabelStatement(node); }
private BoundStatement RewriteForStatement( BoundForStatement node, BoundStatement rewrittenInitializer, BoundExpression rewrittenCondition, BoundStatement rewrittenIncrement, BoundStatement rewrittenBody) { if (node.InnerLocals.IsEmpty) { return(RewriteForStatementWithoutInnerLocals( node, node.OuterLocals, rewrittenInitializer, rewrittenCondition, rewrittenIncrement, rewrittenBody, node.BreakLabel, node.ContinueLabel, node.HasErrors)); } // We need to enter inner_scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // for (initializer; condition; increment) // body; // // becomes the following (with block added for locals) // // { // initializer; // start: // { // GotoIfFalse condition break; // body; // continue: // increment; // goto start; // } // break: // } Debug.Assert(rewrittenBody != null); SyntaxNode syntax = node.Syntax; var statementBuilder = ArrayBuilder <BoundStatement> .GetInstance(); // initializer; if (rewrittenInitializer != null) { statementBuilder.Add(rewrittenInitializer); } var startLabel = new GeneratedLabelSymbol("start"); // start: BoundStatement startLabelStatement = new BoundLabelStatement(syntax, startLabel); if (Instrument) { startLabelStatement = new BoundSequencePoint(null, startLabelStatement); } statementBuilder.Add(startLabelStatement); var blockBuilder = ArrayBuilder <BoundStatement> .GetInstance(); // GotoIfFalse condition break; if (rewrittenCondition != null) { BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, node.BreakLabel); if (this.Instrument) { ifNotConditionGotoBreak = _instrumenter.InstrumentForStatementConditionalGotoStartOrBreak(node, ifNotConditionGotoBreak); } blockBuilder.Add(ifNotConditionGotoBreak); } // body; blockBuilder.Add(rewrittenBody); // continue: // increment; blockBuilder.Add(new BoundLabelStatement(syntax, node.ContinueLabel)); if (rewrittenIncrement != null) { blockBuilder.Add(rewrittenIncrement); } // goto start; blockBuilder.Add(new BoundGotoStatement(syntax, startLabel)); statementBuilder.Add(new BoundBlock(syntax, node.InnerLocals, blockBuilder.ToImmutableAndFree())); // break: statementBuilder.Add(new BoundLabelStatement(syntax, node.BreakLabel)); var statements = statementBuilder.ToImmutableAndFree(); return(new BoundBlock(syntax, node.OuterLocals, statements, node.HasErrors)); }
/// <summary> /// Generate a thread-safe accessor for a regular field-like event. /// /// DelegateType tmp0 = _event; //backing field /// DelegateType tmp1; /// DelegateType tmp2; /// do { /// tmp1 = tmp0; /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); /// } while ((object)tmp0 != (object)tmp1); /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove); MethodSymbol compareExchangeMethod = GetConstructedCompareExchangeMethod(delegateType, compilation, accessor.Locations[0], diagnostics); if ((object)compareExchangeMethod == null) { return new BoundBlock(syntax, locals: ImmutableArray<LocalSymbol>.Empty, statements: ImmutableArray.Create<BoundStatement>( new BoundReturnStatement(syntax, expressionOpt: null) { WasCompilerGenerated = true })) { WasCompilerGenerated = true }; } GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType); } BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) BoundExpression delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create<BoundExpression>(boundTmps[1], boundParameter)), kind: ConversionKind.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create<BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; BoundStatement @return = new BoundReturnStatement(syntax, expressionOpt: null) { WasCompilerGenerated = true }; return new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create<BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }; }
/// <summary> /// Generate a thread-safe accessor for a regular field-like event. /// /// DelegateType tmp0 = _event; //backing field /// DelegateType tmp1; /// DelegateType tmp2; /// do { /// tmp1 = tmp0; /// tmp2 = (DelegateType)Delegate.Combine(tmp1, value); //Remove for -= /// tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); /// } while ((object)tmp0 != (object)tmp1); /// /// Note, if System.Threading.Interlocked.CompareExchange<T> is not available, /// we emit the following code and mark the method Synchronized (unless it is a struct). /// /// _event = (DelegateType)Delegate.Combine(_event, value); //Remove for -= /// /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove; MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId); BoundStatement @return = new BoundReturnStatement(syntax, expressionOpt: null) { WasCompilerGenerated = true }; if (updateMethod == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId); diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name), syntax.Location)); return(new BoundBlock(syntax, locals: ImmutableArray <LocalSymbol> .Empty, statements: ImmutableArray.Create <BoundStatement>(@return)) { WasCompilerGenerated = true }); } Binder.ReportUseSiteDiagnostics(updateMethod, diagnostics, syntax); BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; BoundExpression delegateUpdate; MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); if ((object)compareExchangeMethod == null) { // (DelegateType)Delegate.Combine(_event, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)), kind: ConversionKind.ExplicitReference, type: delegateType); // _event = (DelegateType)Delegate.Combine(_event, value); BoundStatement eventUpdate = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundBackingField, right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: ImmutableArray <LocalSymbol> .Empty, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return)) { WasCompilerGenerated = true }); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSiteDiagnostics(compareExchangeMethod, diagnostics, syntax); GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, delegateType, SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType); } // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)), kind: ConversionKind.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create <BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }); }
private BoundStatement RewriteWhileStatement( BoundWhileStatement loop, ImmutableArray<LocalSymbol> locals, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { if (locals.IsEmpty) { return RewriteWhileStatement(loop, rewrittenCondition, rewrittenBody, breakLabel, continueLabel, hasErrors); } // We need to enter scope-block from the top, that is where an instance of a display class will be created // if any local is captured within a lambda. // while (condition) // body; // // becomes // // continue: // { // GotoIfFalse condition break; // body // goto continue; // } // break: SyntaxNode syntax = loop.Syntax; BoundStatement continueLabelStatement = new BoundLabelStatement(syntax, continueLabel); BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, breakLabel); if (this.Instrument && !loop.WasCompilerGenerated) { ifNotConditionGotoBreak = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak(loop, ifNotConditionGotoBreak); continueLabelStatement = new BoundSequencePoint(null, continueLabelStatement); } return BoundStatementList.Synthesized(syntax, hasErrors, continueLabelStatement, new BoundBlock(syntax, locals, ImmutableArray.Create( ifNotConditionGotoBreak, rewrittenBody, new BoundGotoStatement(syntax, continueLabel))), new BoundLabelStatement(syntax, breakLabel)); }