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); }
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); }
public override BoundNode VisitFieldEqualsValue(BoundFieldEqualsValue node) { AddAll(node.Locals); base.VisitFieldEqualsValue(node); RemoveAll(node.Locals); return(null); }
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); }
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); } }
/// <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); } } } }
/// <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; } } } } }
/// <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); } } } }
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); }