Example #1
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,
            BindingDiagnosticBag 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);

                            if (!boundInitializer.Value.HasAnyErrors)
                            {
                                var field = boundInitializer.Field;
                                if (field.Type.IsRefLikeType)
                                {
                                    BoundExpression value = parentBinder.ValidateEscape(boundInitializer.Value, ExternalScope, isByRef: false, diagnostics);
                                    boundInitializer = boundInitializer.Update(field, boundInitializer.Locals, value);
                                }
                            }

                            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;
                        }
                    }
                }
            }
        }