/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { Debug.Assert((object)scriptCtor != null); firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray <FieldOrPropertyInitializer> siblingInitializers = initializers[i]; // 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; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)initializerNode, diagnostics); } else if (initializerNode.Kind() == SyntaxKind.LabeledStatement) { // TODO: labels in interactive var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray <BoundNode> .Empty, true); boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement); } else { var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(collisionDetector, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray<ImmutableArray<FieldInitializer>> initializers, ArrayBuilder<BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList<Imports> firstDebugImports) { Debug.Assert((object)scriptCtor != null); firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray<FieldInitializer> siblingInitializers = initializers[i]; // 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; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.Field; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportsList; } Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)initializerNode, diagnostics); } else if (initializerNode.Kind == SyntaxKind.LabeledStatement) { // TODO: labels in interactive var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray<BoundNode>.Empty, true); boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement); } else { var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(collisionDetector, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }