internal static void BindFieldInitializers( SourceMemberContainerTypeSymbol typeSymbol, MethodSymbol scriptCtor, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering { DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance(); try { ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; } finally { diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); } }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod?scriptInitializerOpt, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, BindingDiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers ) { var diagsForInstanceInitializers = BindingDiagnosticBag.GetInstance( withDiagnostics: true, diagnostics.AccumulatesDependencies ); ImportChain?firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers( compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain ); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
internal static void BindFieldInitializers( SourceMemberContainerTypeSymbol typeSymbol, MethodSymbol scriptCtor, ImmutableArray <ImmutableArray <FieldInitializer> > fieldInitializers, bool generateDebugInfo, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering { DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance(); try { ConsList <Imports> firstDebugImports; processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers, diagsForInstanceInitializers, generateDebugInfo, out firstDebugImports); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstDebugImports = firstDebugImports; } finally { diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); } }
internal static void BindFieldInitializers( SourceMemberContainerTypeSymbol typeSymbol, MethodSymbol scriptCtor, ImmutableArray<FieldInitializers> fieldInitializers, bool generateDebugInfo, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering { DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance(); try { ConsList<Imports> firstDebugImports; processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers, diagsForInstanceInitializers, generateDebugInfo, out firstDebugImports); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstDebugImports = firstDebugImports; } finally { diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); } }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) { var diagsForInstanceInitializers = DiagnosticBag.GetInstance(); ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers, DiagnosticBag diagnostics, bool setReturnType, // Remove once static fields are errors in submissions. ref ProcessedFieldInitializers processedInitializers) { if (setReturnType && ((object)scriptInitializerOpt != null)) { SetScriptInitializerReturnType(compilation, scriptInitializerOpt, fieldInitializers, diagnostics); } var diagsForInstanceInitializers = DiagnosticBag.GetInstance(); ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, DiagnosticBag diagnostics, bool setReturnType, // Remove once static fields are errors in submissions. ref ProcessedFieldInitializers processedInitializers) { if (setReturnType && ((object)scriptInitializerOpt != null)) { SetScriptInitializerReturnType(compilation, scriptInitializerOpt, fieldInitializers, diagnostics); } var diagsForInstanceInitializers = DiagnosticBag.GetInstance(); ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
internal static void BindFieldInitializers( SourceMemberContainerTypeSymbol typeSymbol, MethodSymbol scriptCtor, ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> fieldInitializers, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) //by ref so that we can store the results of lowering { DiagnosticBag diagsForInstanceInitializers = DiagnosticBag.GetInstance(); try { ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(typeSymbol, scriptCtor, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; } finally { diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); } }
//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; } }
private void CompileNamedType(NamedTypeSymbol symbol) { TypeCompilationState compilationState = new TypeCompilationState(symbol, moduleBeingBuilt); cancellationToken.ThrowIfCancellationRequested(); // Find the constructor of a script class. MethodSymbol scriptCtor = null; if (symbol.IsScriptClass) { // The field initializers of a script class could be arbitrary statements, // including blocks. Field initializers containing blocks need to // use a MethodBodySemanticModel to build up the appropriate tree of binders, and // MethodBodySemanticModel requires an "owning" method. That's why we're digging out // the constructor - it will own the field initializers. scriptCtor = symbol.InstanceConstructors[0]; Debug.Assert((object)scriptCtor != null); } var synthesizedSubmissionFields = symbol.IsSubmissionClass ? new SynthesizedSubmissionFields(compilation, symbol) : null; var processedStaticInitializers = new ProcessedFieldInitializers(); var processedInstanceInitializers = new ProcessedFieldInitializers(); var sourceTypeSymbol = symbol as SourceMemberContainerTypeSymbol; if ((object)sourceTypeSymbol != null) { BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, this.generateDebugInfo, ref processedStaticInitializers); BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, this.generateDebugInfo, ref processedInstanceInitializers); if (compilationState.Emitting) { CompileSynthesizedExplicitImplementations(sourceTypeSymbol, compilationState); } } // Indicates if a static constructor is in the member, // so we can decide to synthesize a static constructor. bool hasStaticConstructor = false; foreach (var member in symbol.GetMembers()) { //When a filter is supplied, limit the compilation of members passing the filter. if ((this.filter != null) && !this.filter(member)) { continue; } switch (member.Kind) { case SymbolKind.NamedType: member.Accept(this, compilationState); break; case SymbolKind.Method: { MethodSymbol method = (MethodSymbol)member; if (method.IsSubmissionConstructor || IsFieldLikeEventAccessor(method)) { continue; } if (method.IsPartial()) { method = method.PartialImplementation(); if ((object)method == null) { continue; } } ProcessedFieldInitializers processedInitializers = method.MethodKind == MethodKind.Constructor ? processedInstanceInitializers : method.MethodKind == MethodKind.StaticConstructor ? processedStaticInitializers : default(ProcessedFieldInitializers); CompileMethod(method, ref processedInitializers, synthesizedSubmissionFields, compilationState); // Set a flag to indicate that a static constructor is created. if (method.MethodKind == MethodKind.StaticConstructor) { hasStaticConstructor = true; } break; } case SymbolKind.Property: { SourcePropertySymbol sourceProperty = member as SourcePropertySymbol; if ((object)sourceProperty != null && sourceProperty.IsSealed && compilationState.Emitting) { CompileSynthesizedSealedAccessors(sourceProperty, compilationState); } break; } case SymbolKind.Event: { SourceEventSymbol eventSymbol = member as SourceEventSymbol; if ((object)eventSymbol != null && eventSymbol.HasAssociatedField && !eventSymbol.IsAbstract && compilationState.Emitting) { CompileFieldLikeEventAccessor(eventSymbol, isAddMethod: true, compilationState: compilationState); CompileFieldLikeEventAccessor(eventSymbol, isAddMethod: false, compilationState: compilationState); } break; } case SymbolKind.Field: { SourceMemberFieldSymbol fieldSymbol = member as SourceMemberFieldSymbol; if ((object)fieldSymbol != null) { if (fieldSymbol.IsConst) { // We check specifically for constant fields with bad values because they never result // in bound nodes being inserted into method bodies (in which case, they would be covered // by the method-level check). ConstantValue constantValue = fieldSymbol.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false); SetGlobalErrorIfTrue(constantValue == null || constantValue.IsBad); } if (fieldSymbol.IsFixed && compilationState.Emitting) { // force the generation of implementation types for fixed-size buffers TypeSymbol discarded = fieldSymbol.FixedImplementationType(compilationState.ModuleBuilder); } } break; } } } Debug.Assert(symbol.TypeKind != TypeKind.Submission || ((object)scriptCtor != null && scriptCtor.IsSubmissionConstructor)); // process additional anonymous type members if (AnonymousTypeManager.IsAnonymousTypeTemplate(symbol)) { ProcessedFieldInitializers processedInitializers = default(ProcessedFieldInitializers); foreach (var method in AnonymousTypeManager.GetAnonymousTypeHiddenMethods(symbol)) { CompileMethod(method, ref processedInitializers, synthesizedSubmissionFields, compilationState); } } // In the case there are field initializers but we haven't created an implicit static constructor (.cctor) for it, // (since we may not add .cctor implicitly created for decimals into the symbol table) // it is necessary for the compiler to generate the static constructor here if we are emitting. if (moduleBeingBuilt != null && !hasStaticConstructor && !processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty) { Debug.Assert(processedStaticInitializers.BoundInitializers.All((init) => (init.Kind == BoundKind.FieldInitializer) && !((BoundFieldInitializer)init).Field.IsMetadataConstant)); MethodSymbol method = new SynthesizedStaticConstructor(sourceTypeSymbol); if ((this.filter == null) || this.filter(method)) { CompileMethod(method, ref processedStaticInitializers, synthesizedSubmissionFields, compilationState); // If this method has been successfully built, we emit it. if (moduleBeingBuilt.GetMethodBody(method) != null) { moduleBeingBuilt.AddCompilerGeneratedDefinition(sourceTypeSymbol, method); } } } // compile submission constructor last so that synthesized submission fields are collected from all script methods: if (synthesizedSubmissionFields != null && compilationState.Emitting) { Debug.Assert(scriptCtor.IsSubmissionConstructor); CompileMethod(scriptCtor, ref processedInstanceInitializers, synthesizedSubmissionFields, compilationState); synthesizedSubmissionFields.AddToType(scriptCtor.ContainingType, compilationState.ModuleBuilder); } // Emit synthesized methods produced during lowering if any CompileGeneratedMethods(compilationState); compilationState.Free(); }