public override BoundNode VisitReturnStatement(BoundReturnStatement node) { EnterStatement(node); BoundSpillSequenceBuilder builder = null; var expression = VisitExpression(ref builder, node.ExpressionOpt); return(UpdateStatement(builder, node.Update(expression), substituteTemps: true)); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundExpression expression = (BoundExpression)this.Visit(node.ExpressionOpt); if (expression == null || expression.Kind != BoundKind.SpillSequence) { return node.Update(expression); } var spillSeq = (BoundSpillSequence)expression; return RewriteSpillSequenceAsBlock(spillSeq, node.Update(spillSeq.Value)); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); if (original.WasCompilerGenerated && original.ExpressionOpt == null && original.Syntax.Kind() == SyntaxKind.Block) { // implicit return added by the compiler return(new BoundSequencePointWithSpan(original.Syntax, rewritten, ((BlockSyntax)original.Syntax).CloseBraceToken.Span)); } return(new BoundSequencePoint(original.Syntax, rewritten)); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { Debug.Assert(_method.IsGenericTaskReturningAsync(F.Compilation)); return(F.Block( F.Assignment(F.Local(_exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(_exprReturnLabel))); } return(F.Goto(_exprReturnLabel)); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundExpression expression = (BoundExpression)this.Visit(node.ExpressionOpt); if (expression == null || expression.Kind != BoundKind.SpillSequence) { return(node.Update(expression)); } var spillSeq = (BoundSpillSequence)expression; return(RewriteSpillSequenceAsBlock(spillSeq, node.Update(spillSeq.Value))); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); // A synthesized return statement that does not return a value never requires instrumentation. // A property set method defined without a block has such a synthesized return statement. if (!_methodHasExplicitBlock && ((BoundReturnStatement)original).ExpressionOpt != null) { // The return statement for value-returning methods defined without a block is compiler generated, but requires instrumentation. return(CollectDynamicAnalysis(original, rewritten)); } return(AddDynamicAnalysis(original, rewritten)); }
/// <summary> /// Construct a body for an auto-property accessor (updating or returning the backing field). /// </summary> internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor) { Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet); var property = (SourcePropertySymbol)accessor.AssociatedSymbol; CSharpSyntaxNode syntax = property.CSharpSyntaxNode; BoundExpression thisReference = null; if (!accessor.IsStatic) { var thisSymbol = accessor.ThisParameter; thisReference = new BoundThisReference(syntax, thisSymbol.Type) { WasCompilerGenerated = true }; } var field = property.BackingField; var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }; BoundStatement statement; if (accessor.MethodKind == MethodKind.PropertyGet) { statement = new BoundReturnStatement(accessor.SyntaxNode, RefKind.None, fieldAccess); } else { Debug.Assert(accessor.MethodKind == MethodKind.PropertySet); var parameter = accessor.Parameters[0]; statement = new BoundExpressionStatement( accessor.SyntaxNode, new BoundAssignmentOperator( syntax, fieldAccess, new BoundParameter(syntax, parameter) { WasCompilerGenerated = true }, property.Type) { WasCompilerGenerated = true }); } return(BoundBlock.SynthesizedNoLocals(syntax, statement)); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return statements if they are contained in lambdas and have expressions. // We do this to ensure that expression lambdas have sequence points, as in Dev10. if (this.generateDebugInfo && (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && this.factory.CurrentMethod is LambdaSymbol))) { // We're not calling AddSequencePoint since it ignores compiler-generated nodes. return new BoundSequencePoint(rewritten.Syntax, rewritten); } return rewritten; }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return statements if they are contained in lambdas and have expressions. // We do this to ensure that expression lambdas have sequence points, as in Dev10. if (this.generateDebugInfo && (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && this.factory.CurrentMethod is LambdaSymbol))) { // We're not calling AddSequencePoint since it ignores compiler-generated nodes. return(new BoundSequencePoint(rewritten.Syntax, rewritten)); } return(rewritten); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); // A synthesized return statement that does not return a value never requires instrumentation. // A property set defined without a block has such a synthesized return statement. // A synthesized return statement that does return a value does require instrumentation. // A method, property get, or lambda defined without a block has such a synthesized return statement. if (ReturnsValueWithinExpressionBodiedConstruct(original)) { // The return statement for value-returning methods defined without a block is compiler generated, but requires instrumentation. return(CollectDynamicAnalysis(original, rewritten)); } return(AddDynamicAnalysis(original, rewritten)); }
// insert the implicit "return" statement at the end of the method body // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these // ones are going to have sequence points. internal static BoundBlock AppendImplicitReturn(BoundBlock body, MethodSymbol method) { Debug.Assert(body != null); Debug.Assert(method != null); SyntaxNode syntax = body.Syntax; Debug.Assert(body.WasCompilerGenerated || syntax.IsKind(SyntaxKind.Block) || syntax.IsKind(SyntaxKind.ArrowExpressionClause) || syntax.IsKind(SyntaxKind.ConstructorDeclaration)); BoundStatement ret = (method.IsIterator && !method.IsAsync) ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax) : BoundReturnStatement.Synthesized(syntax, RefKind.None, null); return(body.Update(body.Locals, body.LocalFunctions, body.Statements.Add(ret))); }
private static bool ReturnsValueWithinExpressionBodiedConstruct(BoundReturnStatement returnStatement) { if (returnStatement.WasCompilerGenerated && returnStatement.ExpressionOpt != null && returnStatement.ExpressionOpt.Syntax != null) { SyntaxKind parentKind = returnStatement.ExpressionOpt.Syntax.Parent.Kind(); switch (parentKind) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ArrowExpressionClause: return(true); } } return(false); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return // statements if they are contained in lambdas and have expressions // or if they are expression-bodied properties. // We do this to ensure that expression lambdas and expression-bodied // properties have sequence points. if (this.GenerateDebugInfo && (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && IsLambdaOrExpressionBodiedMember))) { // We're not calling AddSequencePoint since it ignores compiler-generated nodes. return new BoundSequencePoint(rewritten.Syntax, rewritten); } return rewritten; }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return // statements if they are contained in lambdas and have expressions // or if they are expression-bodied properties. // We do this to ensure that expression lambdas and expression-bodied // properties have sequence points. if (this.GenerateDebugInfo && (!rewritten.WasCompilerGenerated || (node.ExpressionOpt != null && IsLambdaOrExpressionBodiedMember))) { // We're not calling AddSequencePoint since it ignores compiler-generated nodes. return(new BoundSequencePoint(rewritten.Syntax, rewritten)); } return(rewritten); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { var expression = node.ExpressionOpt; if (expression != null) { var returnType = expression.Type; // This is potentially inefficient if there are a large number of returns each with // a different type. This seems unlikely. if (!types.Contains(returnType)) { types.Add(returnType); } } else { hasReturnWithoutArgument = true; } return(null); }
// insert the implicit "return" statement at the end of the method body // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these // ones are going to have sequence points. internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbol method, CSharpSyntaxNode syntax = null) { Debug.Assert(method != null); if (syntax == null) { syntax = node.Syntax; } BoundStatement ret = method.IsIterator ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax) : BoundReturnStatement.Synthesized(syntax, null); if (syntax.Kind() == SyntaxKind.Block) { // Implicitly added return for async method does not need sequence points since lowering would add one. if (!method.IsAsync) { var blockSyntax = (BlockSyntax)syntax; ret = new BoundSequencePointWithSpan( blockSyntax, ret, blockSyntax.CloseBraceToken.Span) { WasCompilerGenerated = true }; } } switch (node.Kind) { case BoundKind.Block: var block = (BoundBlock)node; return(block.Update(block.Locals, block.Statements.Add(ret))); default: return(new BoundBlock(syntax, ImmutableArray <LocalSymbol> .Empty, ImmutableArray.Create(ret, node))); } }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { var result = base.VisitReturnStatement(node); // After processing a return statement, the very last pending branch is for that return statement. // If it is returning an allocated object, consider it to be disposed. if (result != null) { switch (result.Kind) { case HijackedBoundKindForValueHolder: { var holder = (BoundValueHolder)result; var returnBranch = PendingBranches.Last(); foreach (var c in holder.value.creations) { returnBranch.State.possiblyUndisposedCreations.Remove(c); if (returnBranch.State.possiblyDisposedCreations.Contains(c)) { // TODO: error: returning a value that may already have been disposed. } } break; } case BoundKind.NewT: case BoundKind.ObjectCreationExpression: PendingBranches.Last().State.possiblyUndisposedCreations.Remove((BoundExpression)result); break; default: break; } } return(result); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return // statements if they are contained in lambdas and have expressions // or if they are expression-bodied properties. // We do this to ensure that expression lambdas and expression-bodied // properties have sequence points. // We also add sequence points for the implicit "return" statement at the end of the method body // (added by FlowAnalysisPass.AppendImplicitReturn). Implicitly added return for async method // does not need sequence points added here since it would be done later (presumably during Async rewrite). if (this.Instrument && (!node.WasCompilerGenerated || (node.ExpressionOpt != null ? IsLambdaOrExpressionBodiedMember : (node.Syntax.Kind() == SyntaxKind.Block && _factory.CurrentMethod?.IsAsync == false)))) { rewritten = _instrumenter.InstrumentReturnStatement(node, rewritten); } return(rewritten); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundStatement rewritten = (BoundStatement)base.VisitReturnStatement(node); // NOTE: we will apply sequence points to synthesized return // statements if they are contained in lambdas and have expressions // or if they are expression-bodied properties. // We do this to ensure that expression lambdas and expression-bodied // properties have sequence points. // We also add sequence points for the implicit "return" statement at the end of the method body // (added by FlowAnalysisPass.AppendImplicitReturn). Implicitly added return for async method // does not need sequence points added here since it would be done later (presumably during Async rewrite). if (this.Instrument && (!node.WasCompilerGenerated || (node.ExpressionOpt != null ? IsLambdaOrExpressionBodiedMember : (node.Syntax.Kind() == SyntaxKind.Block && _factory.CurrentMethod?.IsAsync == false)))) { rewritten = _instrumenter.InstrumentReturnStatement(node, rewritten); } return rewritten; }
// insert the implicit "return" statement at the end of the method body // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these // ones are going to have sequence points. internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbol method = null, CSharpSyntaxNode syntax = null) { if (syntax == null) { syntax = node.Syntax; } BoundStatement ret = (object)method != null && (object)method.IteratorElementType != null ? BoundYieldBreakStatement.Synthesized(syntax) as BoundStatement : BoundReturnStatement.Synthesized(syntax, null); if (syntax.Kind == SyntaxKind.Block) { var blockSyntax = (BlockSyntax)syntax; ret = new BoundSequencePointWithSpan( blockSyntax, ret, blockSyntax.CloseBraceToken.Span) { WasCompilerGenerated = true }; } switch (node.Kind) { case BoundKind.Block: { var block = (BoundBlock)node; return(block.Update(block.LocalsOpt, block.Statements.Add(ret))); } default: return(new BoundBlock(syntax, ImmutableArray <LocalSymbol> .Empty, ImmutableArray.Create <BoundStatement>(ret, node))); } }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); // A synthesized return statement that does not return a value never requires instrumentation. // A property set method defined without a block has such a synthesized return statement. if (!_methodHasExplicitBlock && ((BoundReturnStatement)original).ExpressionOpt != null) { // The return statement for value-returning methods defined without a block is compiler generated, but requires instrumentation. return CollectDynamicAnalysis(original, rewritten); } return AddDynamicAnalysis(original, rewritten); }
/// <summary> /// Generate a thread-safe accessor for a WinRT field-like event. /// /// Add: /// return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value); /// /// Remove: /// EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value); /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; Debug.Assert((object)accessor != null); FieldSymbol field = eventSymbol.AssociatedField; Debug.Assert((object)field != null); NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type; Debug.Assert(fieldType.Name == "EventRegistrationTokenTable"); MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable, diagnostics, syntax: syntax); if ((object)getOrCreateMethod == null) { Debug.Assert(diagnostics.HasAnyErrors()); return null; } getOrCreateMethod = getOrCreateMethod.AsMember(fieldType); WellKnownMember processHandlerMember = isAddMethod ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler; MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, processHandlerMember, diagnostics, syntax: syntax); if ((object)processHandlerMethod == null) { Debug.Assert(diagnostics.HasAnyErrors()); return null; } processHandlerMethod = processHandlerMethod.AsMember(fieldType); // _tokenTable BoundFieldAccess fieldAccess = new BoundFieldAccess( syntax, field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type), field, constantValueOpt: null) { WasCompilerGenerated = true }; // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable) BoundCall getOrCreateCall = BoundCall.Synthesized( syntax, receiverOpt: null, method: getOrCreateMethod, arguments: fieldAccess); // value BoundParameter parameterAccess = new BoundParameter( syntax, accessor.Parameters.Single()); // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler BoundCall processHandlerCall = BoundCall.Synthesized( syntax, receiverOpt: getOrCreateCall, method: processHandlerMethod, arguments: parameterAccess); if (isAddMethod) { // { // return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value); // } BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall); return BoundBlock.SynthesizedNoLocals(syntax, returnStatement); } else { // { // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value); // return; // } BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall); BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null); return BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement); } }
/// <summary> /// Construct a body for an auto-property accessor (updating or returning the backing field). /// </summary> internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor) { Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet); var property = (SourcePropertySymbol)accessor.AssociatedSymbol; CSharpSyntaxNode syntax = property.CSharpSyntaxNode; BoundExpression thisReference = null; if (!accessor.IsStatic) { var thisSymbol = accessor.ThisParameter; thisReference = new BoundThisReference(syntax, thisSymbol.Type) { WasCompilerGenerated = true }; } var field = property.BackingField; var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }; BoundStatement statement; if (accessor.MethodKind == MethodKind.PropertyGet) { statement = new BoundReturnStatement(syntax, fieldAccess) { WasCompilerGenerated = true }; } else { Debug.Assert(accessor.MethodKind == MethodKind.PropertySet); var parameter = accessor.Parameters[0]; statement = new BoundExpressionStatement( syntax, new BoundAssignmentOperator( syntax, fieldAccess, new BoundParameter(syntax, parameter) { WasCompilerGenerated = true }, property.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; } statement = new BoundSequencePoint(accessor.SyntaxNode, statement) { WasCompilerGenerated = true }; return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true }; }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { return Previous.InstrumentReturnStatement(original, rewritten); }
/// <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 }; }
private BoundStatement UnpendBranches( AwaitFinallyFrame frame, SynthesizedLocal pendingBranchVar, SynthesizedLocal pendingException) { var parent = frame.ParentOpt; // handle proxy labels if have any var proxiedLabels = frame.proxiedLabels; // skip 0 - it means we took no explicit branches int i = 1; var cases = ArrayBuilder <BoundSwitchSection> .GetInstance(); if (proxiedLabels != null) { for (int cnt = proxiedLabels.Count; i <= cnt; i++) { var target = proxiedLabels[i - 1]; var parentProxy = parent.ProxyLabelIfNeeded(target); var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy)); cases.Add(caseStatement); } } if (frame.returnProxyLabel != null) { BoundLocal pendingValue = null; if (frame.returnValue != null) { pendingValue = _F.Local(frame.returnValue); } SynthesizedLocal returnValue; BoundStatement unpendReturn; var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentFunction, pendingValue, out returnValue); if (returnLabel == null) { unpendReturn = new BoundReturnStatement(_F.Syntax, RefKind.None, pendingValue); } else { if (pendingValue == null) { unpendReturn = _F.Goto(returnLabel); } else { unpendReturn = _F.Block( _F.Assignment( _F.Local(returnValue), pendingValue), _F.Goto(returnLabel)); } } var caseStatement = _F.SwitchSection(i, unpendReturn); cases.Add(caseStatement); } return(_F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree())); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { var expression = node.ExpressionOpt; if (expression != null) { var returnType = expression.Type; // This is potentially inefficient if there are a large number of returns each with // a different type. This seems unlikely. if (!_types.Contains(returnType)) { _types.Add(returnType); } } else { _hasReturnWithoutArgument = true; } return null; }
/// <summary> /// Generate a thread-safe accessor for a WinRT field-like event. /// /// Add: /// return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddEventHandler(value); /// /// Remove: /// EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveEventHandler(value); /// </summary> internal static BoundBlock ConstructFieldLikeEventAccessorBody_WinRT(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, DiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; Debug.Assert((object)accessor != null); FieldSymbol field = eventSymbol.AssociatedField; Debug.Assert((object)field != null); NamedTypeSymbol fieldType = (NamedTypeSymbol)field.Type; Debug.Assert(fieldType.Name == "EventRegistrationTokenTable"); MethodSymbol getOrCreateMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__GetOrCreateEventRegistrationTokenTable, diagnostics, syntax: syntax); if ((object)getOrCreateMethod == null) { Debug.Assert(diagnostics.HasAnyErrors()); return(null); } getOrCreateMethod = getOrCreateMethod.AsMember(fieldType); WellKnownMember processHandlerMember = isAddMethod ? WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__AddEventHandler : WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T__RemoveEventHandler; MethodSymbol processHandlerMethod = (MethodSymbol)Binder.GetWellKnownTypeMember( compilation, processHandlerMember, diagnostics, syntax: syntax); if ((object)processHandlerMethod == null) { Debug.Assert(diagnostics.HasAnyErrors()); return(null); } processHandlerMethod = processHandlerMethod.AsMember(fieldType); // _tokenTable BoundFieldAccess fieldAccess = new BoundFieldAccess( syntax, field.IsStatic ? null : new BoundThisReference(syntax, accessor.ThisParameter.Type), field, constantValueOpt: null) { WasCompilerGenerated = true }; // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable) BoundCall getOrCreateCall = BoundCall.Synthesized( syntax, receiverOpt: null, method: getOrCreateMethod, arg0: fieldAccess); // value BoundParameter parameterAccess = new BoundParameter( syntax, accessor.Parameters.Single()); // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value) // or RemoveHandler BoundCall processHandlerCall = BoundCall.Synthesized( syntax, receiverOpt: getOrCreateCall, method: processHandlerMethod, arg0: parameterAccess); if (isAddMethod) { // { // return EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).AddHandler(value); // } BoundStatement returnStatement = BoundReturnStatement.Synthesized(syntax, processHandlerCall); return(BoundBlock.SynthesizedNoLocals(syntax, returnStatement)); } else { // { // EventRegistrationTokenTable<Event>.GetOrCreateEventRegistrationTokenTable(ref _tokenTable).RemoveHandler(value); // return; // } BoundStatement callStatement = new BoundExpressionStatement(syntax, processHandlerCall); BoundStatement returnStatement = new BoundReturnStatement(syntax, expressionOpt: null); return(BoundBlock.SynthesizedNoLocals(syntax, callStatement, returnStatement)); } }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { BoundSpillSequence2 ss = null; var expression = VisitExpression(ref ss, node.ExpressionOpt); return UpdateStatement(ss, node.Update(expression)); }
/// <summary> /// Wrap a given expression e into a block as either { e; } or { return e; } /// Shared between lambda and expression-bodied method binding. /// </summary> internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableArray<LocalSymbol> locals, RefKind refKind, BoundExpression expression, ExpressionSyntax expressionSyntax, DiagnosticBag diagnostics) { RefKind returnRefKind; var returnType = GetCurrentReturnType(out returnRefKind); var syntax = expressionSyntax ?? expression.Syntax; BoundStatement statement; if (IsInAsyncMethod() && refKind != RefKind.None) { // This can happen if we are binding an async anonymous method to a delegate type. Error(diagnostics, ErrorCode.ERR_MustNotHaveRefReturn, syntax); statement = new BoundReturnStatement(syntax, refKind, expression) { WasCompilerGenerated = true }; } else if ((object)returnType != null) { if ((refKind != RefKind.None) != (returnRefKind != RefKind.None)) { var errorCode = refKind != RefKind.None ? ErrorCode.ERR_MustNotHaveRefReturn : ErrorCode.ERR_MustHaveRefReturn; Error(diagnostics, errorCode, syntax); statement = new BoundReturnStatement(syntax, RefKind.None, expression) { WasCompilerGenerated = true }; } else if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. Debug.Assert(expressionSyntax != null || !IsValidStatementExpression(expression.Syntax, expression)); bool errors = false; if (expressionSyntax == null || !IsValidStatementExpression(expressionSyntax, expression)) { Error(diagnostics, ErrorCode.ERR_IllegalStatement, syntax); errors = true; } // Don't mark compiler generated so that the rewriter generates sequence points var expressionStatement = new BoundExpressionStatement(syntax, expression, errors); CheckForUnobservedAwaitable(expression, diagnostics); statement = expressionStatement; } else { expression = CreateReturnConversion(syntax, diagnostics, expression, refKind, returnType); statement = new BoundReturnStatement(syntax, returnRefKind, expression) { WasCompilerGenerated = true }; } } else if (expression.Type?.SpecialType == SpecialType.System_Void) { statement = new BoundExpressionStatement(syntax, expression) { WasCompilerGenerated = true }; } else { statement = new BoundReturnStatement(syntax, refKind, expression) { WasCompilerGenerated = true }; } // Need to attach the tree for when we generate sequence points. return new BoundBlock(node, locals, ImmutableArray<LocalFunctionSymbol>.Empty, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause }; }
/// <summary> /// Wrap a given expression e into a block as either { e; } or { return e; } /// Shared between lambda and expression-bodied method binding. /// </summary> internal BoundBlock CreateBlockFromExpression(CSharpSyntaxNode node, ImmutableArray<LocalSymbol> locals, ExpressionSyntax expressionSyntax, BoundExpression expression, DiagnosticBag diagnostics) { var returnType = GetCurrentReturnType(); var syntax = expressionSyntax ?? expression.Syntax; BoundStatement statement; if ((object)returnType != null) { if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. Debug.Assert(expressionSyntax != null || !IsValidStatementExpression(expression.Syntax, expression)); bool errors = false; if (expressionSyntax == null || !IsValidStatementExpression(expressionSyntax, expression)) { Error(diagnostics, ErrorCode.ERR_IllegalStatement, syntax); errors = true; } // Don't mark compiler generated so that the rewriter generates sequence points var expressionStatement = new BoundExpressionStatement(syntax, expression, errors); CheckForUnobservedAwaitable(expressionStatement, diagnostics); statement = expressionStatement; } else { expression = CreateReturnConversion(syntax, diagnostics, expression, returnType); statement = new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true }; } } else if (expression.Type?.SpecialType == SpecialType.System_Void) { statement = new BoundExpressionStatement(syntax, expression) { WasCompilerGenerated = true }; } else { statement = new BoundReturnStatement(syntax, expression) { WasCompilerGenerated = true }; } // Need to attach the tree for when we generate sequence points. return new BoundBlock(node, locals, ImmutableArray.Create(statement)) { WasCompilerGenerated = node.Kind() != SyntaxKind.ArrowExpressionClause }; }
public virtual BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { return rewritten; }
private BoundStatement UnpendBranches( AwaitFinallyFrame frame, SynthesizedLocal pendingBranchVar, SynthesizedLocal pendingException) { var parent = frame.ParentOpt; // 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; var cases = ArrayBuilder<BoundSwitchSection>.GetInstance(); if (proxiedLabels != null) { for (int cnt = proxiedLabels.Count; i <= cnt; i++) { var target = proxiedLabels[i - 1]; var parentProxy = parent.ProxyLabelIfNeeded(target); var caseStatement = _F.SwitchSection(i, _F.Goto(parentProxy)); cases.Add(caseStatement); } } if (frame.returnProxyLabel != null) { BoundLocal pendingValue = null; if (frame.returnValue != null) { pendingValue = _F.Local(frame.returnValue); } SynthesizedLocal returnValue; BoundStatement unpendReturn; var returnLabel = parent.ProxyReturnIfNeeded(_F.CurrentMethod, pendingValue, out returnValue); if (returnLabel == null) { unpendReturn = new BoundReturnStatement(_F.Syntax, pendingValue); } else { if (pendingValue == null) { unpendReturn = _F.Goto(returnLabel); } else { unpendReturn = _F.Block( _F.Assignment( _F.Local(returnValue), pendingValue), _F.Goto(returnLabel)); } } var caseStatement = _F.SwitchSection(i, unpendReturn); cases.Add(caseStatement); } return _F.Switch(_F.Local(pendingBranchVar), cases.ToImmutableAndFree()); }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { SynthesizedLocal returnValue; var returnLabel = _currentAwaitFinallyFrame.ProxyReturnIfNeeded( _F.CurrentMethod, node.ExpressionOpt, out returnValue); if (returnLabel == null) { return base.VisitReturnStatement(node); } var returnExpr = (BoundExpression)(this.Visit(node.ExpressionOpt)); if (returnExpr != null) { return _F.Block( _F.Assignment( _F.Local(returnValue), returnExpr), _F.Goto( returnLabel)); } else { return _F.Goto(returnLabel); } }
private static bool ReturnsValueWithinExpressionBodiedConstruct(BoundReturnStatement returnStatement) { if (returnStatement.WasCompilerGenerated && returnStatement.ExpressionOpt != null && returnStatement.ExpressionOpt.Syntax != null) { SyntaxKind parentKind = returnStatement.ExpressionOpt.Syntax.Parent.Kind(); switch (parentKind) { case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ArrowExpressionClause: return true; } } return false; }
public override BoundNode VisitReturnStatement(BoundReturnStatement node) { if (node.ExpressionOpt != null) { Debug.Assert(method.IsGenericTaskReturningAsync()); return F.Block( F.Assignment(F.Local(exprRetValue), (BoundExpression)Visit(node.ExpressionOpt)), F.Goto(exprReturnLabel)); } return F.Goto(exprReturnLabel); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); // A synthesized return statement that does not return a value never requires instrumentation. // A property set defined without a block has such a synthesized return statement. // A synthesized return statement that does return a value does require instrumentation. // A method, property get, or lambda defined without a block has such a synthesized return statement. if (ReturnsValueWithinExpressionBodiedConstruct(original)) { // The return statement for value-returning methods defined without a block is compiler generated, but requires instrumentation. return CollectDynamicAnalysis(original, rewritten); } return AddDynamicAnalysis(original, rewritten); }
internal BoundBlock WrapExpressionLambdaBody(BoundExpression expression, CSharpSyntaxNode node, DiagnosticBag diagnostics) { var returnType = this.GetCurrentReturnType(); BoundStatement statement; if ((object)returnType != null) { if (returnType.SpecialType == SpecialType.System_Void || IsTaskReturningAsyncMethod()) { // If the return type is void then the expression is required to be a legal // statement expression. bool errors = false; if (!IsValidStatementExpression(node, expression)) { Error(diagnostics, ErrorCode.ERR_IllegalStatement, node); errors = true; } var expressionStatement = new BoundExpressionStatement(expression.Syntax, expression, errors); CheckForUnobservedAwaitable(expressionStatement, diagnostics); statement = expressionStatement; } else { expression = CreateReturnConversion(node, diagnostics, expression, returnType); statement = new BoundReturnStatement(expression.Syntax, expression) { WasCompilerGenerated = true }; } } else if ((object)expression.Type != null && expression.Type.SpecialType == SpecialType.System_Void) { statement = new BoundExpressionStatement(expression.Syntax, expression) { WasCompilerGenerated = true }; } else { statement = new BoundReturnStatement(expression.Syntax, expression) { WasCompilerGenerated = true }; } // Need to attach the tree for when we generate sequence points. var block = new BoundBlock(node, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create<BoundStatement>(statement)) { WasCompilerGenerated = true }; return block; }
/// <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 }); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { rewritten = base.InstrumentReturnStatement(original, rewritten); if (original.WasCompilerGenerated && original.ExpressionOpt == null && original.Syntax.Kind() == SyntaxKind.Block) { // implicit return added by the compiler return new BoundSequencePointWithSpan(original.Syntax, rewritten, ((BlockSyntax)original.Syntax).CloseBraceToken.Span); } return new BoundSequencePoint(original.Syntax, rewritten); }
public override BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { return(Previous.InstrumentReturnStatement(original, rewritten)); }
public virtual BoundStatement InstrumentReturnStatement(BoundReturnStatement original, BoundStatement rewritten) { return(rewritten); }