Exemplo n.º 1
0
        private static BoundFieldEqualsValue BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode,
                                                                  DiagnosticBag diagnostics)
        {
            Debug.Assert(!fieldSymbol.IsMetadataConstant);

            var fieldsBeingBound = binder.FieldsBeingBound;

            var  sourceField            = fieldSymbol as SourceMemberFieldSymbolFromDeclarator;
            bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound);

            // If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here:
            // CONSIDER (tomat): reusing the bound field initializers for implicitly typed fields.
            DiagnosticBag initializerDiagnostics;

            if (isImplicitlyTypedField)
            {
                initializerDiagnostics = DiagnosticBag.GetInstance();
            }
            else
            {
                initializerDiagnostics = diagnostics;
            }

            binder = new ExecutableCodeBinder(equalsValueClauseNode, fieldSymbol, new LocalScopeBinder(binder));
            BoundFieldEqualsValue boundInitValue = binder.BindFieldInitializer(fieldSymbol, equalsValueClauseNode, initializerDiagnostics);

            if (isImplicitlyTypedField)
            {
                initializerDiagnostics.Free();
            }

            return(boundInitValue);
        }
Exemplo n.º 2
0
        public static ConstantValue EvaluateFieldConstant(
            SourceFieldSymbol symbol,
            EqualsValueClauseSyntax equalsValueNode,
            HashSet <SourceFieldSymbolWithSyntaxReference> dependencies,
            bool earlyDecodingWellKnownAttributes,
            BindingDiagnosticBag diagnostics)
        {
            var compilation   = symbol.DeclaringCompilation;
            var binderFactory = compilation.GetBinderFactory((SyntaxTree)symbol.Locations[0].SourceTree);
            var binder        = binderFactory.GetBinder(equalsValueNode);

            if (earlyDecodingWellKnownAttributes)
            {
                binder = new EarlyWellKnownAttributeBinder(binder);
            }
            var inProgressBinder             = new ConstantFieldsInProgressBinder(new ConstantFieldsInProgress(symbol, dependencies), binder);
            BoundFieldEqualsValue boundValue = BindFieldOrEnumInitializer(inProgressBinder, symbol, equalsValueNode, diagnostics);
            var initValueNodeLocation        = equalsValueNode.Value.Location;

            var value = GetAndValidateConstantValue(boundValue.Value, symbol, symbol.Type, initValueNodeLocation, diagnostics);

            Debug.Assert(value != null);

            return(value);
        }
Exemplo n.º 3
0
 public override BoundNode VisitFieldEqualsValue(BoundFieldEqualsValue node)
 {
     AddAll(node.Locals);
     base.VisitFieldEqualsValue(node);
     RemoveAll(node.Locals);
     return(null);
 }
Exemplo n.º 4
0
        private static BoundStatement RewriteFieldInitializer(BoundFieldEqualsValue fieldInit)
        {
            SyntaxNode syntax = fieldInit.Syntax;

            syntax = (syntax as EqualsValueClauseSyntax)?.Value ?? syntax; //we want the attached sequence point to indicate the value node
            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.Value,
                                                                         fieldInit.Field.Type.TypeSymbol)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = !fieldInit.Locals.IsEmpty || fieldInit.WasCompilerGenerated
            };

            if (!fieldInit.Locals.IsEmpty)
            {
                boundStatement = new BoundBlock(syntax, fieldInit.Locals, ImmutableArray.Create(boundStatement))
                {
                    WasCompilerGenerated = fieldInit.WasCompilerGenerated
                };
            }

            Debug.Assert(LocalRewriter.IsFieldOrPropertyInitializer(boundStatement));
            return(boundStatement);
        }
Exemplo n.º 5
0
        private BoundEqualsValue BindEqualsValue(
            Binder binder,
            EqualsValueClauseSyntax equalsValue,
            BindingDiagnosticBag diagnostics
            )
        {
            switch (this.MemberSymbol.Kind)
            {
            case SymbolKind.Field:
            {
                var field     = (FieldSymbol)this.MemberSymbol;
                var enumField = field as SourceEnumConstantSymbol;
                if ((object)enumField != null)
                {
                    return(binder.BindEnumConstantInitializer(
                               enumField,
                               equalsValue,
                               diagnostics
                               ));
                }
                else
                {
                    return(binder.BindFieldInitializer(field, equalsValue, diagnostics));
                }
            }

            case SymbolKind.Property:
            {
                var property = (SourcePropertySymbol)this.MemberSymbol;
                BoundFieldEqualsValue result = binder.BindFieldInitializer(
                    property.BackingField,
                    equalsValue,
                    diagnostics
                    );
                return(new BoundPropertyEqualsValue(
                           result.Syntax,
                           property,
                           result.Locals,
                           result.Value
                           ));
            }

            case SymbolKind.Parameter:
            {
                var parameter = (ParameterSymbol)this.MemberSymbol;
                return(binder.BindParameterDefaultValue(
                           equalsValue,
                           parameter,
                           diagnostics,
                           out _
                           ));
            }

            default:
                throw ExceptionUtilities.UnexpectedValue(this.MemberSymbol.Kind);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// In regular C#, all field initializers are assignments to fields and the assigned expressions
        /// may not reference instance members.
        /// </summary>
        internal static void BindRegularCSharpFieldInitializers(
            CSharpCompilation compilation,
            ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers,
            ArrayBuilder <BoundInitializer> boundInitializers,
            DiagnosticBag diagnostics,
            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 is TypeSymbol containing && TypeSymbol.Equals(containing, fieldSymbol.ContainingType, TypeCompareKind.ConsiderEverything2)) || //should be the binder for the type
                                     fieldSymbol.ContainingType.IsImplicitClass);                                                                                                                          //however, we also allow fields in namespaces to help support script scenarios

                        if (firstDebugImports == null)
                        {
                            firstDebugImports = parentBinder.ImportChain;
                        }

                        parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);

                        BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
                        boundInitializers.Add(boundInitializer);
                    }
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// In regular C#, all field initializers are assignments to fields and the assigned expressions
        /// may not reference instance members.
        /// </summary>
        internal static void BindRegularCSharpFieldInitializers(
            CSharpCompilation compilation,
            ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers,
            ArrayBuilder <BoundInitializer> boundInitializers,
            DiagnosticBag diagnostics,
            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;

                        switch (syntaxRef.GetSyntax())
                        {
                        case EqualsValueClauseSyntax initializerNode:
                            if (binderFactory == null)
                            {
                                binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
                            }

                            Binder parentBinder = binderFactory.GetBinder(initializerNode);

                            if (firstDebugImports == null)
                            {
                                firstDebugImports = parentBinder.ImportChain;
                            }

                            parentBinder = parentBinder.GetFieldInitializerBinder(fieldSymbol);

                            BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
                            boundInitializers.Add(boundInitializer);
                            break;

                        case ParameterSyntax parameterSyntax:     // Initializer for a generated property based on record parameters

                            if (firstDebugImports == null)
                            {
                                if (binderFactory == null)
                                {
                                    binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
                                }

                                firstDebugImports = binderFactory.GetBinder(parameterSyntax).ImportChain;
                            }

                            boundInitializers.Add(new BoundFieldEqualsValue(parameterSyntax, fieldSymbol, ImmutableArray <LocalSymbol> .Empty,
                                                                            new BoundParameter(parameterSyntax,
                                                                                               ((SynthesizedRecordPropertySymbol)fieldSymbol.AssociatedSymbol).BackingParameter).MakeCompilerGenerated()));
                            break;

                        default:
                            throw ExceptionUtilities.Unreachable;
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// In regular C#, all field initializers are assignments to fields and the assigned expressions
        /// may not reference instance members.
        /// </summary>
        internal static void BindRegularCSharpFieldInitializers(
            CSharpCompilation compilation,
            ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers,
            ArrayBuilder <BoundInitializer> boundInitializers,
            DiagnosticBag diagnostics,
            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;

#if XSHARP
                        if (syntaxRef.GetSyntax().IsKind(SyntaxKind.VariableDeclarator) || syntaxRef.GetSyntax().IsKind(SyntaxKind.PropertyDeclaration))
                        {
                            // note that inside SourceMemberContailerSymbol we have added initializers of the wrong type
                            // we handle that here and create the BoundFieldEqualValue wanted by Roslyn
                            var variable = (CSharpSyntaxNode)syntaxRef.GetSyntax();
                            if (binderFactory == null)
                            {
                                binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
                            }
                            Binder pb = binderFactory.GetBinder(variable);
                            Debug.Assert(pb.ContainingMemberOrLambda == fieldSymbol.ContainingType || fieldSymbol.ContainingType.IsImplicitClass);
                            if (firstDebugImports == null)
                            {
                                firstDebugImports = pb.ImportChain;
                            }
                            TypeSymbol type = fieldSymbol.Type;
                            var        cv   = ConstantValue.Create("", type.SpecialType);

                            var eqvalue = new BoundFieldEqualsValue(variable,
                                                                    fieldSymbol,
                                                                    ImmutableArray <LocalSymbol> .Empty,
                                                                    new BoundLiteral(variable, cv, type)
                            {
                                WasCompilerGenerated = true
                            }
                                                                    )
                            {
                                WasCompilerGenerated = true
                            };
                            boundInitializers.Add(eqvalue);
                            continue;
                        }
#endif
                        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 (firstDebugImports == null)
                        {
                            firstDebugImports = parentBinder.ImportChain;
                        }

                        parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol);

                        BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics);
                        boundInitializers.Add(boundInitializer);
                    }
                }
            }
        }
Exemplo n.º 9
0
        private static BoundStatement RewriteFieldInitializer(BoundFieldEqualsValue fieldInit)
        {
            var syntax = fieldInit.Syntax;

            syntax = (syntax as EqualsValueClauseSyntax)?.Value ?? syntax; //we want the attached sequence point to indicate the value node
            var boundReceiver = fieldInit.Field.IsStatic ? null :
                                new BoundThisReference(syntax, fieldInit.Field.ContainingType);

#if XSHARP
            var initValue = fieldInit.Value;
            // a generated initial value for VO NULL_STRING initialization
            // should not overwrite a value set in a child class
            // not that we recommend that <g>
            bool wasGenerated = fieldInit.WasCompilerGenerated;
            if (!wasGenerated)
            {
                var xNode = initValue.Syntax as LiteralExpressionSyntax;
                if (xNode != null && xNode.XGenerated)
                {
                    wasGenerated = true;
                }
            }
            if (wasGenerated && fieldInit.Field.Type.IsStringType() &&
                boundReceiver != null &&
                fieldInit.Field.DeclaringCompilation.Options.HasOption(CompilerOption.NullStrings, boundReceiver.Syntax))
            {
                var fldaccess = new BoundFieldAccess(syntax,
                                                     boundReceiver,
                                                     fieldInit.Field,
                                                     constantValueOpt: null)
                {
                    WasCompilerGenerated = true
                };
                initValue = new BoundNullCoalescingOperator(syntax,
                                                            fldaccess,
                                                            initValue,
                                                            Conversion.Identity,
                                                            fieldInit.Field.Type)
                {
                    WasCompilerGenerated = true
                };
            }
            BoundStatement boundStatement =
                new BoundExpressionStatement(syntax,
                                             new BoundAssignmentOperator(syntax,
                                                                         new BoundFieldAccess(syntax,
                                                                                              boundReceiver,
                                                                                              fieldInit.Field,
                                                                                              constantValueOpt: null),
                                                                         initValue,
                                                                         fieldInit.Field.Type)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = fieldInit.WasCompilerGenerated
            };
#else
            BoundStatement boundStatement =
                new BoundExpressionStatement(syntax,
                                             new BoundAssignmentOperator(syntax,
                                                                         new BoundFieldAccess(syntax,
                                                                                              boundReceiver,
                                                                                              fieldInit.Field,
                                                                                              constantValueOpt: null),
                                                                         fieldInit.Value,
                                                                         fieldInit.Field.Type)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = !fieldInit.Locals.IsEmpty || fieldInit.WasCompilerGenerated
            };
#endif
            if (!fieldInit.Locals.IsEmpty)
            {
                boundStatement = new BoundBlock(syntax, fieldInit.Locals, ImmutableArray.Create(boundStatement))
                {
                    WasCompilerGenerated = fieldInit.WasCompilerGenerated
                };
            }

            Debug.Assert(LocalRewriter.IsFieldOrPropertyInitializer(boundStatement));
            return(boundStatement);
        }