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 BoundNode VisitMultipleLocalDeclarationsBase(BoundMultipleLocalDeclarationsBase node) { ArrayBuilder <BoundStatement> inits = null; foreach (var decl in node.LocalDeclarations) { var init = VisitLocalDeclaration(decl); if (init != null) { if (inits == null) { inits = ArrayBuilder <BoundStatement> .GetInstance(); } inits.Add((BoundStatement)init); } } if (inits != null) { return(BoundStatementList.Synthesized(node.Syntax, node.HasErrors, inits.ToImmutableAndFree())); } else { // no initializers return(null); // TODO: but what if hasErrors? Have we lost that? } }
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)); }
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)); }
private BoundStatement RewriteWhileStatement( BoundLoopStatement loop, BoundExpression rewrittenCondition, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { Debug.Assert(loop.Kind == BoundKind.WhileStatement || loop.Kind == BoundKind.ForEachStatement); // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: SyntaxNode syntax = loop.Syntax; var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.Instrument && !loop.WasCompilerGenerated) { switch (loop.Kind) { case BoundKind.WhileStatement: ifConditionGotoStart = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak((BoundWhileStatement)loop, ifConditionGotoStart); break; case BoundKind.ForEachStatement: ifConditionGotoStart = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)loop, ifConditionGotoStart); break; default: throw ExceptionUtilities.UnexpectedValue(loop.Kind); } // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } return(BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel))); }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; // 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 condition are being executed. if (!node.WasCompilerGenerated && this.Instrument) { rewrittenCondition = _instrumenter.InstrumentDoStatementCondition(node, rewrittenCondition, _factory); } BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, rewrittenCondition, true, startLabel); if (!node.WasCompilerGenerated && this.Instrument) { ifConditionGotoStart = _instrumenter.InstrumentDoStatementConditionalGotoStart(node, ifConditionGotoStart); } // do // body // while (condition); // // becomes // // start: // { // body // continue: // sequence point // GotoIfTrue condition start; // } // break: if (node.Locals.IsEmpty) { return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel))); } return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), new BoundBlock(syntax, node.Locals, ImmutableArray.Create <BoundStatement>(rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart)), new BoundLabelStatement(syntax, node.BreakLabel))); }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { var doSyntax = (DoStatementSyntax)syntax; var span = TextSpan.FromBounds( doSyntax.WhileKeyword.SpanStart, doSyntax.SemicolonToken.Span.End); ifConditionGotoStart = new BoundSequencePointWithSpan(doSyntax, ifConditionGotoStart, span); } // do // body // while (condition); // // becomes // // start: // { // body // continue: // sequence point // GotoIfTrue condition start; // } // break: if (!node.InnerLocals.IsDefaultOrEmpty) { return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), new BoundBlock(syntax, node.InnerLocals, ImmutableArray.Create <BoundStatement>(rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart)), new BoundLabelStatement(syntax, node.BreakLabel))); } return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel))); }
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))); }
private static BoundStatement RewriteIfStatement( CSharpSyntaxNode syntax, BoundExpression rewrittenCondition, BoundStatement rewrittenConsequence, BoundStatement rewrittenAlternativeOpt, bool hasErrors) { var afterif = new GeneratedLabelSymbol("afterif"); // if (condition) // consequence; // // becomes // // GotoIfFalse condition afterif; // consequence; // afterif: if (rewrittenAlternativeOpt == null) { return(BoundStatementList.Synthesized(syntax, new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, afterif), rewrittenConsequence, new BoundLabelStatement(syntax, afterif))); } // if (condition) // consequence; // else // alternative // // becomes // // GotoIfFalse condition alt; // consequence // goto afterif; // alt: // alternative; // afterif: var alt = new GeneratedLabelSymbol("alternative"); return(BoundStatementList.Synthesized(syntax, hasErrors, new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, alt), rewrittenConsequence, new BoundGotoStatement(syntax, afterif), new BoundLabelStatement(syntax, alt), rewrittenAlternativeOpt, new BoundLabelStatement(syntax, afterif))); }
private BoundStatement RewriteWhileStatement( CSharpSyntaxNode syntax, BoundExpression rewrittenCondition, TextSpan conditionSequencePointSpan, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); if (this.GenerateDebugInfo) { ifConditionGotoStart = new BoundSequencePointWithSpan(syntax, ifConditionGotoStart, conditionSequencePointSpan); } // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.GenerateDebugInfo) { // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } return(BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel))); }
public override BoundNode VisitExpressionStatement(BoundExpressionStatement node) { var syntax = node.Syntax; var loweredExpression = VisitUnusedExpression(node.Expression); if (loweredExpression == null) { // NOTE: not using a BoundNoOpStatement, since we don't want a nop to be emitted. // CONSIDER: could use a BoundNoOpStatement (DevDiv #12943). return(BoundStatementList.Synthesized(syntax)); } else { return(AddSequencePoint(node.Update(loweredExpression))); } }
public override BoundNode VisitDoStatement(BoundDoStatement node) { Debug.Assert(node != null); var rewrittenCondition = (BoundExpression)Visit(node.Condition); var rewrittenBody = (BoundStatement)Visit(node.Body); var startLabel = new GeneratedLabelSymbol("start"); var syntax = node.Syntax; // 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 condition are being executed. BoundStatement ifConditionGotoStart = new BoundConditionalGoto(syntax, AddConditionSequencePoint(rewrittenCondition, node), true, startLabel); if (this.GenerateDebugInfo) { var doSyntax = (DoStatementSyntax)syntax; var span = TextSpan.FromBounds( doSyntax.WhileKeyword.SpanStart, doSyntax.SemicolonToken.Span.End); ifConditionGotoStart = new BoundSequencePointWithSpan(doSyntax, ifConditionGotoStart, span); } // do // body // while (condition); // // becomes // // start: // { // body // continue: // sequence point // GotoIfTrue condition start; // } // break: return(BoundStatementList.Synthesized(syntax, node.HasErrors, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, node.ContinueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, node.BreakLabel))); }
public override BoundNode VisitLocalDeconstructionDeclaration(BoundLocalDeconstructionDeclaration node) { var syntax = node.Syntax; var loweredExpression = VisitUnusedExpression(node.Assignment); if (loweredExpression == null) { // NOTE: not using a BoundNoOpStatement, since we don't want a nop to be emitted. // CONSIDER: could use a BoundNoOpStatement (DevDiv #12943). return(BoundStatementList.Synthesized(syntax)); } else { BoundStatement result = new BoundExpressionStatement(loweredExpression.Syntax, loweredExpression, node.HasErrors); result.WasCompilerGenerated = node.WasCompilerGenerated; if (this.Instrument && !node.WasCompilerGenerated) { result = _instrumenter.InstrumentLocalDeconstructionDeclaration(node, result); } return(result); } }
public override BoundNode VisitExpressionStatement(BoundExpressionStatement node) { // NOTE: not using a BoundNoOpStatement, since we don't want a nop to be emitted. // CONSIDER: could use a BoundNoOpStatement (DevDiv #12943). return(RewriteExpressionStatement(node) ?? BoundStatementList.Synthesized(node.Syntax)); }
private BoundStatement RewriteWhileStatement( CSharpSyntaxNode syntax, ImmutableArray <LocalSymbol> innerLocals, BoundExpression rewrittenCondition, TextSpan conditionSequencePointSpan, BoundStatement rewrittenBody, GeneratedLabelSymbol breakLabel, GeneratedLabelSymbol continueLabel, bool hasErrors) { if (!innerLocals.IsDefaultOrEmpty) { var walker = new AnyLocalCapturedInALambdaWalker(innerLocals); if (walker.Analyze(rewrittenCondition) || walker.Analyze(rewrittenBody)) { // If any inner local is captured within a lambda, we need to enter scope-block // always from the top, that is where an instance of a display class will be created. // The IL will be less optimal, but this shouldn't be a problem, given presence of lambdas. // while (condition) // body; // // becomes // // continue: // { // GotoIfFalse condition break; // body // goto continue; // } // break: // TODO: We could perform more fine analysis. // If locals declared in condition (the innerLocals) are captured, but not referenced in the body, we could use optimal IL by creating // another block around the condition and use it as a scope for the locals declared in condition. // This optimization can be applied to 'for' as well, while-body === for-body + increment. // Note however that the scope adjusments will likely be observable during debugging, in locals window. BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, breakLabel); if (this.generateDebugInfo) { ifNotConditionGotoBreak = new BoundSequencePointWithSpan(syntax, ifNotConditionGotoBreak, conditionSequencePointSpan); } return(BoundStatementList.Synthesized(syntax, hasErrors, new BoundLabelStatement(syntax, continueLabel), new BoundBlock(syntax, innerLocals, ImmutableArray.Create <BoundStatement>( ifNotConditionGotoBreak, rewrittenBody, new BoundGotoStatement(syntax, continueLabel))), new BoundLabelStatement(syntax, breakLabel))); } } var startLabel = new GeneratedLabelSymbol("start"); BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel); if (this.generateDebugInfo) { ifConditionGotoStart = new BoundSequencePointWithSpan(syntax, ifConditionGotoStart, conditionSequencePointSpan); } // while (condition) // body; // // becomes // // goto continue; // start: // { // body // continue: // GotoIfTrue condition start; // } // break: BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel); if (this.generateDebugInfo) { // mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This // jump may be a target of another jump (for example if loops are nested) and that would give the // impression that the previous statement is being re-executed. gotoContinue = new BoundSequencePoint(null, gotoContinue); } if (!innerLocals.IsDefaultOrEmpty) { return(BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), new BoundBlock(syntax, innerLocals, ImmutableArray.Create <BoundStatement>( rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart)), new BoundLabelStatement(syntax, breakLabel))); } return(BoundStatementList.Synthesized(syntax, hasErrors, gotoContinue, new BoundLabelStatement(syntax, startLabel), rewrittenBody, new BoundLabelStatement(syntax, continueLabel), ifConditionGotoStart, new BoundLabelStatement(syntax, breakLabel))); }
//TODO: it might be nice to make this a static method on Compiler private void CompileMethod( MethodSymbol methodSymbol, ref ProcessedFieldInitializers processedInitializers, SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState) { cancellationToken.ThrowIfCancellationRequested(); SourceMethodSymbol sourceMethod = methodSymbol as SourceMethodSymbol; if (methodSymbol.IsAbstract) { if ((object)sourceMethod != null) { bool diagsWritten; sourceMethod.SetDiagnostics(ImmutableArray <Diagnostic> .Empty, out diagsWritten); if (diagsWritten && !methodSymbol.IsImplicitlyDeclared && compilation.EventQueue != null) { compilation.SymbolDeclaredEvent(methodSymbol); } } return; } // get cached diagnostics if not building and we have 'em bool calculateDiagnosticsOnly = moduleBeingBuilt == null; if (calculateDiagnosticsOnly && ((object)sourceMethod != null)) { var cachedDiagnostics = sourceMethod.Diagnostics; if (!cachedDiagnostics.IsDefault) { this.diagnostics.AddRange(cachedDiagnostics); return; } } ConsList <Imports> oldDebugImports = compilationState.CurrentDebugImports; // In order to avoid generating code for methods with errors, we create a diagnostic bag just for this method. DiagnosticBag diagsForCurrentMethod = DiagnosticBag.GetInstance(); try { bool includeInitializersInBody; BoundBlock body; // if synthesized method returns its body in lowered form if (methodSymbol.SynthesizesLoweredBoundBody) { if (moduleBeingBuilt != null) { methodSymbol.GenerateMethodBody(compilationState, diagsForCurrentMethod); this.diagnostics.AddRange(diagsForCurrentMethod); } return; } //EDMAURER initializers that have been analyzed but not yet lowered. BoundStatementList analyzedInitializers = null; ConsList <Imports> debugImports; if (methodSymbol.IsScriptConstructor) { // rewrite top-level statements and script variable declarations to a list of statements and assignments, respectively: BoundStatementList initializerStatements = InitializerRewriter.Rewrite(processedInitializers.BoundInitializers, methodSymbol); // the lowered script initializers should not be treated as initializers anymore but as a method body: body = new BoundBlock(initializerStatements.Syntax, ImmutableArray <LocalSymbol> .Empty, initializerStatements.Statements) { WasCompilerGenerated = true }; includeInitializersInBody = false; debugImports = null; } else { // do not emit initializers if we are invoking another constructor of this class: includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty && !HasThisConstructorInitializer(methodSymbol); // lower initializers just once. the lowered tree will be reused when emitting all constructors // with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers // (see later in this method). Don't bother lowering _now_ if this particular ctor won't have the initializers // appended to its body. if (includeInitializersInBody && processedInitializers.LoweredInitializers == null) { analyzedInitializers = InitializerRewriter.Rewrite(processedInitializers.BoundInitializers, methodSymbol); processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors; // These analyses check for diagnostics in lambdas. // Control flow analysis and implicit return insertion are unnecessary. DataFlowPass.Analyze(compilation, methodSymbol, analyzedInitializers, diagsForCurrentMethod, requireOutParamsAssigned: false); DiagnosticsPass.IssueDiagnostics(compilation, analyzedInitializers, diagsForCurrentMethod, methodSymbol); } body = Compiler.BindMethodBody(methodSymbol, diagsForCurrentMethod, this.generateDebugInfo, out debugImports); } #if DEBUG // If the method is a synthesized static or instance constructor, then debugImports will be null and we will use the value // from the first field initializer. if (this.generateDebugInfo) { if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) && methodSymbol.IsImplicitlyDeclared) { // There was no body to bind, so we didn't get anything from Compiler.BindMethodBody. Debug.Assert(debugImports == null); // Either there were no field initializers or we grabbed debug imports from the first one. Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstDebugImports != null); } } #endif debugImports = debugImports ?? processedInitializers.FirstDebugImports; // Associate these debug imports with all methods generated from this one. compilationState.CurrentDebugImports = debugImports; if (body != null && methodSymbol is SourceMethodSymbol) { // TODO: Do we need to issue warnings for non-SourceMethodSymbol methods, like synthesized ctors? DiagnosticsPass.IssueDiagnostics(compilation, body, diagsForCurrentMethod, methodSymbol); } BoundBlock flowAnalyzedBody = null; if (body != null) { flowAnalyzedBody = FlowAnalysisPass.Rewrite(methodSymbol, body, diagsForCurrentMethod); } bool hasErrors = hasDeclarationErrors || diagsForCurrentMethod.HasAnyErrors() || processedInitializers.HasErrors; // Record whether or not the bound tree for the lowered method body (including any initializers) contained any // errors (note: errors, not diagnostics). SetGlobalErrorIfTrue(hasErrors); bool diagsWritten = false; var actualDiagnostics = diagsForCurrentMethod.ToReadOnly(); if (sourceMethod != null) { actualDiagnostics = sourceMethod.SetDiagnostics(actualDiagnostics, out diagsWritten); } if (diagsWritten && !methodSymbol.IsImplicitlyDeclared && compilation.EventQueue != null) { var lazySemanticModel = body == null ? null : new Lazy <SemanticModel>(() => { var syntax = body.Syntax; var semanticModel = (CSharpSemanticModel)compilation.GetSemanticModel(syntax.SyntaxTree); var memberModel = semanticModel.GetMemberModel(syntax); if (memberModel != null) { memberModel.AddBoundTreeForStandaloneSyntax(syntax, body); } return(semanticModel); }); compilation.EventQueue.Enqueue(new CompilationEvent.SymbolDeclared(compilation, methodSymbol, lazySemanticModel)); } // Don't lower if we're not emitting or if there were errors. // Methods that had binding errors are considered too broken to be lowered reliably. if (calculateDiagnosticsOnly || hasErrors) { this.diagnostics.AddRange(actualDiagnostics); return; } // ############################ // LOWERING AND EMIT // Any errors generated below here are considered Emit diagnostics // and will not be reported to callers Compilation.GetDiagnostics() BoundStatement loweredBody = (flowAnalyzedBody == null) ? null : Compiler.LowerStatement(this.generateDebugInfo, methodSymbol, flowAnalyzedBody, previousSubmissionFields, compilationState, diagsForCurrentMethod); bool hasBody = loweredBody != null; hasErrors = hasErrors || (hasBody && loweredBody.HasErrors) || diagsForCurrentMethod.HasAnyErrors(); SetGlobalErrorIfTrue(hasErrors); // don't emit if the resulting method would contain initializers with errors if (!hasErrors && (hasBody || includeInitializersInBody)) { // Fields must be initialized before constructor initializer (which is the first statement of the analyzed body, if specified), // so that the initialization occurs before any method overridden by the declaring class can be invoked from the base constructor // and access the fields. ImmutableArray <BoundStatement> boundStatements; if (methodSymbol.IsScriptConstructor) { boundStatements = MethodBodySynthesizer.ConstructScriptConstructorBody(loweredBody, methodSymbol, previousSubmissionFields, compilation); } else { boundStatements = ImmutableArray <BoundStatement> .Empty; if (analyzedInitializers != null) { processedInitializers.LoweredInitializers = (BoundStatementList)Compiler.LowerStatement( this.generateDebugInfo, methodSymbol, analyzedInitializers, previousSubmissionFields, compilationState, diagsForCurrentMethod); Debug.Assert(!hasErrors); hasErrors = processedInitializers.LoweredInitializers.HasAnyErrors || diagsForCurrentMethod.HasAnyErrors(); SetGlobalErrorIfTrue(hasErrors); if (hasErrors) { this.diagnostics.AddRange(diagsForCurrentMethod); return; } } // initializers for global code have already been included in the body if (includeInitializersInBody) { //TODO: rewrite any BoundThis and BoundBase nodes in the initializers to have the correct ThisParameter symbol if (compilation.Options.Optimize) { // TODO: this part may conflict with InitializerRewriter.Rewrite in how it handles // the first field initializer (see 'if (i == 0)'...) which seems suspicious ArrayBuilder <BoundStatement> statements = ArrayBuilder <BoundStatement> .GetInstance(); statements.AddRange(boundStatements); bool anyNonDefault = false; foreach (var initializer in processedInitializers.LoweredInitializers.Statements) { if (ShouldOptimizeOutInitializer(initializer)) { if (methodSymbol.IsStatic) { // NOTE: Dev11 removes static initializers if ONLY all of them are optimized out statements.Add(initializer); } } else { statements.Add(initializer); anyNonDefault = true; } } if (anyNonDefault) { boundStatements = statements.ToImmutableAndFree(); } else { statements.Free(); } } else { boundStatements = boundStatements.Concat(processedInitializers.LoweredInitializers.Statements); } } if (hasBody) { boundStatements = boundStatements.Concat(ImmutableArray.Create(loweredBody)); } } CSharpSyntaxNode syntax = methodSymbol.GetNonNullSyntaxNode(); var boundBody = BoundStatementList.Synthesized(syntax, boundStatements); var emittedBody = Compiler.GenerateMethodBody( compilationState, methodSymbol, boundBody, diagsForCurrentMethod, optimize, debugDocumentProvider, GetNamespaceScopes(methodSymbol, debugImports)); moduleBeingBuilt.SetMethodBody(methodSymbol, emittedBody); } this.diagnostics.AddRange(diagsForCurrentMethod); } finally { diagsForCurrentMethod.Free(); compilationState.CurrentDebugImports = oldDebugImports; } }