Exemple #1
0
        /// <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();
            }
        }
Exemple #2
0
        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);
                    }
                }
            }
        }
Exemple #4
0
        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()));
                }
            }
        }