private static ImmutableArray <BoundInitializer> BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, DiagnosticBag diagnostics, out ImportChain firstImportChain) { if (initializers.IsEmpty) { firstImportChain = null; return(ImmutableArray <BoundInitializer> .Empty); } var boundInitializers = ArrayBuilder <BoundInitializer> .GetInstance(); if ((object)scriptInitializerOpt == null) { BindRegularCSharpFieldInitializers(compilation, initializers, boundInitializers, diagnostics, out firstImportChain); } else { BindScriptFieldInitializers(compilation, scriptInitializerOpt, initializers, boundInitializers, diagnostics, out firstImportChain); } return(boundInitializers.ToImmutableAndFree()); }
private static void SetScriptInitializerReturnType( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializer, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, DiagnosticBag diagnostics) { bool isAsync = scriptInitializer.IsSubmissionInitializer && fieldInitializers.Any(i => i.Any(ContainsAwaitsVisitor.ContainsAwait)); var resultType = scriptInitializer.ResultType; TypeSymbol returnType; if ((object)resultType == null) { Debug.Assert(!isAsync); returnType = compilation.GetSpecialType(SpecialType.System_Void); } else if (!isAsync) { returnType = resultType; } else { var taskT = compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T); var useSiteDiagnostic = taskT.GetUseSiteDiagnostic(); if (useSiteDiagnostic != null) { diagnostics.Add(useSiteDiagnostic, NoLocation.Singleton); } returnType = taskT.Construct(resultType); } scriptInitializer.SetReturnType(isAsync, returnType); }
private static BoundInitializer BindGlobalStatement( Binder binder, SynthesizedInteractiveInitializerMethod scriptInitializer, StatementSyntax statementNode, DiagnosticBag diagnostics, bool isLast) { BoundStatement boundStatement = binder.BindStatement(statementNode, diagnostics); // the result of the last global expression is assigned to the result storage for submission result: if (binder.Compilation.IsSubmission && isLast && !boundStatement.HasAnyErrors) { // insert an implicit conversion for the submission return type (if needed): var expression = InitializerRewriter.GetTrailingScriptExpression(boundStatement); if (expression != null && ((object)expression.Type == null || expression.Type.SpecialType != SpecialType.System_Void)) { var submissionResultType = scriptInitializer.ResultType; expression = binder.GenerateConversionForAssignment(submissionResultType, expression, diagnostics); boundStatement = new BoundExpressionStatement(boundStatement.Syntax, expression, expression.HasErrors); } } return(new BoundGlobalStatementInitializer(statementNode, boundStatement)); }
internal Labels( SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax ) { _scriptInitializer = scriptInitializer; _syntax = syntax; }
/// <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, SynthesizedInteractiveInitializerMethod scriptInitializer, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, BindingDiagnosticBag diagnostics, out ImportChain?firstDebugImports ) { 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; // Label instances must be shared across all global statements. ScriptLocalScopeBinder.Labels?labels = 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; var syntaxTree = syntaxRef.SyntaxTree; Debug.Assert(syntaxTree.Options.Kind != SourceCodeKind.Regular); var syntax = (CSharpSyntaxNode)syntaxRef.GetSyntax(); var syntaxRoot = syntaxTree.GetCompilationUnitRoot(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxTree); labels = new ScriptLocalScopeBinder.Labels(scriptInitializer, syntaxRoot); } Binder scriptClassBinder = binderFactory.GetBinder(syntax); Debug.Assert( scriptClassBinder.ContainingMemberOrLambda is NamedTypeSymbol { IsScriptClass: true }
private static ImmutableArray <LabelSymbol> GetLabels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax) { var builder = ArrayBuilder <LabelSymbol> .GetInstance(); foreach (var member in syntax.Members) { if (member.Kind() != SyntaxKind.GlobalStatement) { continue; } LocalScopeBinder.BuildLabels(scriptInitializer, ((GlobalStatementSyntax)member).Statement, ref builder); } return(builder.ToImmutableAndFree()); }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, DiagnosticBag diagnostics, ref ProcessedFieldInitializers processedInitializers) { var diagsForInstanceInitializers = DiagnosticBag.GetInstance(); ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
private static BoundInitializer BindGlobalStatement( Binder binder, SynthesizedInteractiveInitializerMethod scriptInitializer, StatementSyntax statementNode, DiagnosticBag diagnostics, bool isLast) { var statement = binder.BindStatement(statementNode, diagnostics); if (isLast && !statement.HasAnyErrors) { // the result of the last global expression is assigned to the result storage for submission result: if (binder.Compilation.IsSubmission) { // insert an implicit conversion for the submission return type (if needed): var expression = InitializerRewriter.GetTrailingScriptExpression(statement); if (expression != null && ((object)expression.Type == null || expression.Type.SpecialType != SpecialType.System_Void)) { var submissionResultType = scriptInitializer.ResultType; expression = binder.GenerateConversionForAssignment(submissionResultType, expression, diagnostics); statement = new BoundExpressionStatement(statement.Syntax, expression, expression.HasErrors); } } // don't allow trailing expressions after labels (as in regular C#, labels must be followed by a statement): if (statement.Kind == BoundKind.LabeledStatement) { var labeledStatementBody = ((BoundLabeledStatement)statement).Body; while (labeledStatementBody.Kind == BoundKind.LabeledStatement) { labeledStatementBody = ((BoundLabeledStatement)labeledStatementBody).Body; } if (InitializerRewriter.GetTrailingScriptExpression(labeledStatementBody) != null) { Error(diagnostics, ErrorCode.ERR_SemicolonExpected, ((ExpressionStatementSyntax)labeledStatementBody.Syntax).SemicolonToken); } } } return(new BoundGlobalStatementInitializer(statementNode, statement)); }
internal static void BindFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializerOpt, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > fieldInitializers, DiagnosticBag diagnostics, bool setReturnType, // Remove once static fields are errors in submissions. ref ProcessedFieldInitializers processedInitializers) { if (setReturnType && ((object)scriptInitializerOpt != null)) { SetScriptInitializerReturnType(compilation, scriptInitializerOpt, fieldInitializers, diagnostics); } var diagsForInstanceInitializers = DiagnosticBag.GetInstance(); ImportChain firstImportChain; processedInitializers.BoundInitializers = BindFieldInitializers(compilation, scriptInitializerOpt, fieldInitializers, diagsForInstanceInitializers, out firstImportChain); processedInitializers.HasErrors = diagsForInstanceInitializers.HasAnyErrors(); processedInitializers.FirstImportChain = firstImportChain; diagnostics.AddRange(diagsForInstanceInitializers); diagsForInstanceInitializers.Free(); }
/// <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, SynthesizedInteractiveInitializerMethod scriptInitializer, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { 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(), scriptInitializer, 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, scriptInitializer, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
internal static BoundTypeOrInstanceInitializers RewriteScriptInitializer(ImmutableArray <BoundInitializer> boundInitializers, SynthesizedInteractiveInitializerMethod method, out bool hasTrailingExpression) { Debug.Assert(!boundInitializers.IsDefault); var boundStatements = ArrayBuilder <BoundStatement> .GetInstance(boundInitializers.Length); var submissionResultType = method.ResultType; var hasSubmissionResultType = (object)submissionResultType != null; BoundStatement lastStatement = null; BoundExpression trailingExpression = null; foreach (var initializer in boundInitializers) { // The value of the last expression statement (if any) is returned from the submission initializer, // unless this is a #load'ed tree. I the #load'ed tree case, we'll execute the trailing expression // but discard its result. if (hasSubmissionResultType && (initializer == boundInitializers.Last()) && (initializer.Kind == BoundKind.GlobalStatementInitializer) && method.DeclaringCompilation.IsSubmissionSyntaxTree(initializer.SyntaxTree)) { lastStatement = ((BoundGlobalStatementInitializer)initializer).Statement; var expression = GetTrailingScriptExpression(lastStatement); if (expression != null && (object)expression.Type != null && expression.Type.SpecialType != SpecialType.System_Void) { trailingExpression = expression; continue; } } boundStatements.Add(RewriteInitializersAsStatements(initializer)); } if (hasSubmissionResultType && (trailingExpression != null)) { Debug.Assert(submissionResultType.SpecialType != SpecialType.System_Void); // Note: The trailing expression was already converted to the submission result type in Binder.BindGlobalStatement. boundStatements.Add(new BoundReturnStatement(lastStatement.Syntax, RefKind.None, trailingExpression)); hasTrailingExpression = true; } else { hasTrailingExpression = false; } return(new BoundTypeOrInstanceInitializers(method.GetNonNullSyntaxNode(), boundStatements.ToImmutableAndFree())); }
internal static BoundTypeOrInstanceInitializers RewriteScriptInitializer(ImmutableArray <BoundInitializer> boundInitializers, SynthesizedInteractiveInitializerMethod method) { Debug.Assert(!boundInitializers.IsDefault); var boundStatements = ArrayBuilder <BoundStatement> .GetInstance(boundInitializers.Length); var submissionResultType = method.ResultType; BoundExpression submissionResult = null; foreach (var initializer in boundInitializers) { // The value of the last expression statement (if any) is returned from the submission initializer. if (((object)submissionResultType != null) && (initializer == boundInitializers.Last()) && (initializer.Kind == BoundKind.GlobalStatementInitializer)) { var statement = ((BoundGlobalStatementInitializer)initializer).Statement; if (statement.Kind == BoundKind.ExpressionStatement) { var expr = ((BoundExpressionStatement)statement).Expression; if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void) { submissionResult = expr; continue; } } } boundStatements.Add(RewriteInitializersAsStatements(initializer)); } var syntax = method.GetNonNullSyntaxNode(); if ((object)submissionResultType != null) { if (submissionResult == null) { // Return default(T) if submission does not have a trailing expression. submissionResult = new BoundDefaultOperator(syntax, submissionResultType); } Debug.Assert(submissionResult.Type.SpecialType != SpecialType.System_Void); // The expression is converted to the submission result type when the initializer is bound. boundStatements.Add(new BoundReturnStatement(submissionResult.Syntax, submissionResult)); } return(new BoundTypeOrInstanceInitializers(syntax, boundStatements.ToImmutableAndFree())); }