/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> private static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <FieldInitializers> initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList <Imports> firstDebugImports) { firstDebugImports = null; foreach (FieldInitializers siblingInitializers in initializers) { var infos = ArrayBuilder <FieldInitializerInfo> .GetInstance(); // Exact size is not known up front. var locals = GetFieldInitializerInfos(compilation, siblingInitializers, infos, generateDebugInfo, ref firstDebugImports); ArrayBuilder <BoundInitializer> initializersBuilder = locals.IsDefaultOrEmpty ? boundInitializers : ArrayBuilder <BoundInitializer> .GetInstance(infos.Count); foreach (var info in infos) { BoundFieldInitializer boundInitializer = BindFieldInitializer(info.Binder, info.Initializer.Field, info.EqualsValue, diagnostics); initializersBuilder.Add(boundInitializer); } Debug.Assert(locals.IsDefaultOrEmpty == (initializersBuilder == boundInitializers)); if (!locals.IsDefaultOrEmpty) { boundInitializers.Add(new BoundInitializationScope((CSharpSyntaxNode)siblingInitializers.TypeDeclarationSyntax.GetSyntax(), locals, initializersBuilder.ToImmutableAndFree())); } infos.Free(); } }
private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fieldInit) { var syntax = fieldInit.Syntax; var boundReceiver = fieldInit.Field.IsStatic ? null : new BoundThisReference(syntax, fieldInit.Field.ContainingType); BoundStatement boundStatement = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, boundReceiver, fieldInit.Field, constantValueOpt: null), fieldInit.InitialValue, fieldInit.Field.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = fieldInit.WasCompilerGenerated }; Debug.Assert(LocalRewriter.IsFieldOrPropertyInitializer(boundStatement)); return(boundStatement); }
/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> private static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ImportChain firstDebugImports) { firstDebugImports = null; foreach (ImmutableArray <FieldOrPropertyInitializer> siblingInitializers in initializers) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; foreach (FieldOrPropertyInitializer initializer in siblingInitializers) { FieldSymbol fieldSymbol = initializer.FieldOpt; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportChain; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); boundInitializers.Add(boundInitializer); } } } }
private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fieldInit) { var syntax = fieldInit.Syntax; var boundReceiver = fieldInit.Field.IsStatic ? null : new BoundThisReference(syntax, fieldInit.Field.ContainingType); // Mark this as CompilerGenerated so that the local rewriter doesn't add a sequence point. BoundStatement boundStatement = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, boundReceiver, fieldInit.Field, constantValueOpt: null), fieldInit.InitialValue, fieldInit.Field.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; Debug.Assert(syntax is ExpressionSyntax); // Should be the initial value. Debug.Assert(syntax.Parent.Kind == SyntaxKind.EqualsValueClause); switch (syntax.Parent.Parent.Kind) { case SyntaxKind.VariableDeclarator: var declaratorSyntax = (VariableDeclaratorSyntax)syntax.Parent.Parent; boundStatement = LocalRewriter.AddSequencePoint(declaratorSyntax, boundStatement); break; case SyntaxKind.PropertyDeclaration: var declaration = (PropertyDeclarationSyntax)syntax.Parent.Parent; boundStatement = LocalRewriter.AddSequencePoint(declaration, boundStatement); break; default: throw ExceptionUtilities.Unreachable; } return(boundStatement); }
private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fieldInit) { var syntax = fieldInit.Syntax; var boundReceiver = fieldInit.Field.IsStatic ? null : new BoundThisReference(syntax, fieldInit.Field.ContainingType); BoundStatement boundStatement = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, boundReceiver, fieldInit.Field, constantValueOpt: null), fieldInit.InitialValue, fieldInit.Field.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = fieldInit.WasCompilerGenerated }; Debug.Assert(LocalRewriter.IsFieldOrPropertyInitializer(boundStatement)); return boundStatement; }
private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fieldInit) { var syntax = fieldInit.Syntax; var boundReceiver = fieldInit.Field.IsStatic ? null : new BoundThisReference(syntax, fieldInit.Field.ContainingType); // Mark this as CompilerGenerated so that the local rewriter doesn't add a sequence point. BoundStatement boundStatement = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, boundReceiver, fieldInit.Field, constantValueOpt: null), fieldInit.InitialValue, fieldInit.Field.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; Debug.Assert(syntax is ExpressionSyntax); // Should be the initial value. Debug.Assert(syntax.Parent.Kind() == SyntaxKind.EqualsValueClause); switch (syntax.Parent.Parent.Kind()) { case SyntaxKind.VariableDeclarator: var declaratorSyntax = (VariableDeclaratorSyntax)syntax.Parent.Parent; boundStatement = LocalRewriter.AddSequencePoint(declaratorSyntax, boundStatement); break; case SyntaxKind.PropertyDeclaration: var declaration = (PropertyDeclarationSyntax)syntax.Parent.Parent; boundStatement = LocalRewriter.AddSequencePoint(declaration, boundStatement); break; default: throw ExceptionUtilities.UnexpectedValue(syntax.Parent.Parent.Kind()); } return boundStatement; }
/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> private static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <FieldInitializers> initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList <Imports> firstDebugImports) { firstDebugImports = null; foreach (FieldInitializers siblingInitializers in initializers) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; var infos = ArrayBuilder <FieldInitializerInfo> .GetInstance(); // Exact size is not known up front. foreach (FieldInitializer initializer in siblingInitializers.Initializers) { FieldSymbol fieldSymbol = initializer.Field; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportsList; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); if (!fieldSymbol.IsConst && !fieldSymbol.IsStatic) { parentBinder = parentBinder.WithPrimaryConstructorParametersIfNecessary(fieldSymbol.ContainingType); } infos.Add(new FieldInitializerInfo(initializer, parentBinder, initializerNode)); } } // See if there are locals that we need to bring into the scope. var locals = default(ImmutableArray <LocalSymbol>); if (siblingInitializers.TypeDeclarationSyntax != null) { locals = GetInitializationScopeLocals(infos); } ArrayBuilder <BoundInitializer> initializersBuilder = locals.IsDefaultOrEmpty ? boundInitializers : ArrayBuilder <BoundInitializer> .GetInstance(infos.Count); foreach (var info in infos) { Binder binder = info.Binder; ScopedExpressionBinder scopedExpressionBinder = null; // Constant initializers is not part of the initialization scope. if (info.Initializer.Field.IsConst || locals.IsDefault) { binder = scopedExpressionBinder = new ScopedExpressionBinder(binder, info.EqualsValue.Value); } else if (!locals.IsEmpty) { binder = new SimpleLocalScopeBinder(locals, binder); } BoundFieldInitializer boundInitializer = BindFieldInitializer(binder, info.Initializer.Field, info.EqualsValue, diagnostics); if (scopedExpressionBinder != null && !scopedExpressionBinder.Locals.IsDefaultOrEmpty) { boundInitializer = boundInitializer.Update(boundInitializer.Field, scopedExpressionBinder.AddLocalScopeToExpression(boundInitializer.InitialValue)); } initializersBuilder.Add(boundInitializer); } Debug.Assert(locals.IsDefaultOrEmpty == (initializersBuilder == boundInitializers)); if (!locals.IsDefaultOrEmpty) { boundInitializers.Add(new BoundInitializationScope((CSharpSyntaxNode)siblingInitializers.TypeDeclarationSyntax.GetSyntax(), locals, initializersBuilder.ToImmutableAndFree())); } } }