/// <summary>
        /// The flow analysis pass.  This pass reports required diagnostics for unreachable
        /// statements and uninitialized variables (through the call to FlowAnalysisWalker.Analyze),
        /// and inserts a final return statement if the end of a void-returning method is reachable.
        /// </summary>
        /// <param name="method">the method to be analyzed</param>
        /// <param name="block">the method's body</param>
        /// <param name="diagnostics">the receiver of the reported diagnostics</param>
        /// <param name="hasTrailingExpression">indicates whether this Script had a trailing expression</param>
        /// <param name="originalBodyNested">the original method body is the last statement in the block</param>
        /// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns>
        public static BoundBlock Rewrite(
            MethodSymbol method,
            BoundBlock block,
            DiagnosticBag diagnostics,
            bool hasTrailingExpression,
            bool originalBodyNested)
        {
#if DEBUG
            // We should only see a trailingExpression if we're in a Script initializer.
            Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer);
            var initialDiagnosticCount = diagnostics.ToReadOnly().Length;
#endif
            var compilation = method.DeclaringCompilation;

            if (method.ReturnsVoid || method.IsIterator ||
                (method.IsAsync && compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) == method.ReturnType))
            {
                // we don't analyze synthesized void methods.
                if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) || Analyze(compilation, method, block, diagnostics))
                {
                    block = AppendImplicitReturn(block, method, (CSharpSyntaxNode)(method as SourceMethodSymbol)?.BodySyntax, originalBodyNested);
                }
            }
            else if (Analyze(compilation, method, block, diagnostics))
            {
                // If the method is a lambda expression being converted to a non-void delegate type
                // and the end point is reachable then suppress the error here; a special error
                // will be reported by the lambda binder.
                Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction);

                // Add implicit "return default(T)" if this is a submission that does not have a trailing expression.
                var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType;
                if (!hasTrailingExpression && ((object)submissionResultType != null))
                {
                    Debug.Assert(submissionResultType.SpecialType != SpecialType.System_Void);

                    var trailingExpression = new BoundDefaultOperator(method.GetNonNullSyntaxNode(), submissionResultType);
                    var newStatements = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, trailingExpression));
                    block = new BoundBlock(block.Syntax, ImmutableArray<LocalSymbol>.Empty, newStatements) { WasCompilerGenerated = true };
#if DEBUG
                    // It should not be necessary to repeat analysis after adding this node, because adding a trailing
                    // return in cases where one was missing should never produce different Diagnostics.
                    var flowAnalysisDiagnostics = DiagnosticBag.GetInstance();
                    Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics));
                    Debug.Assert(flowAnalysisDiagnostics.ToReadOnly().SequenceEqual(diagnostics.ToReadOnly().Skip(initialDiagnosticCount)));
                    flowAnalysisDiagnostics.Free();
#endif
                }
                // If there's more than one location, then the method is partial and we
                // have already reported a non-void partial method error.
                else if (method.Locations.Length == 1)
                {
                    diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method);
                }
            }

            return block;
        }
Beispiel #2
0
        internal static BoundTypeOrInstanceInitializers RewriteConstructor(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol method)
        {
            Debug.Assert(!boundInitializers.IsDefault);
            Debug.Assert((method.MethodKind == MethodKind.Constructor) || (method.MethodKind == MethodKind.StaticConstructor));

            var sourceMethod = method as SourceMethodSymbol;
            var syntax = ((object)sourceMethod != null) ? sourceMethod.SyntaxNode : method.GetNonNullSyntaxNode();
            return new BoundTypeOrInstanceInitializers(syntax, boundInitializers.SelectAsArray(RewriteInitializersAsStatements));
        }
        internal static BoundCall GenerateObjectConstructorInitializer(MethodSymbol constructor, DiagnosticBag diagnostics)
        {
            NamedTypeSymbol objectType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics;
            Debug.Assert(objectType.SpecialType == SpecialType.System_Object);
            MethodSymbol objectConstructor = null;
            LookupResultKind resultKind = LookupResultKind.Viable;

            foreach (MethodSymbol objectCtor in objectType.InstanceConstructors)
            {
                if (objectCtor.ParameterCount == 0)
                {
                    objectConstructor = objectCtor;
                    break;
                }
            }

            // UNDONE: If this happens then something is deeply wrong. Should we give a better error?
            if ((object)objectConstructor == null)
            {
                diagnostics.Add(ErrorCode.ERR_BadCtorArgCount, constructor.Locations[0], objectType, /*desired param count*/ 0);
                return null;
            }

            // UNDONE: If this happens then something is deeply wrong. Should we give a better error?
            bool hasErrors = false;
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            if (!AccessCheck.IsSymbolAccessible(objectConstructor, constructor.ContainingType, ref useSiteDiagnostics))
            {
                diagnostics.Add(ErrorCode.ERR_BadAccess, constructor.Locations[0], objectConstructor);
                resultKind = LookupResultKind.Inaccessible;
                hasErrors = true;
            }

            if (!useSiteDiagnostics.IsNullOrEmpty())
            {
                diagnostics.Add(constructor.Locations.IsEmpty ? NoLocation.Singleton : constructor.Locations[0], useSiteDiagnostics);
            }

            CSharpSyntaxNode syntax = constructor.GetNonNullSyntaxNode();

            BoundExpression receiver = new BoundThisReference(syntax, constructor.ContainingType) { WasCompilerGenerated = true };
            return new BoundCall(
                syntax: syntax,
                receiverOpt: receiver,
                method: objectConstructor,
                arguments: ImmutableArray<BoundExpression>.Empty,
                argumentNamesOpt: ImmutableArray<string>.Empty,
                argumentRefKindsOpt: ImmutableArray<RefKind>.Empty,
                isDelegateCall: false,
                expanded: false,
                invokedAsExtensionMethod: false,
                argsToParamsOpt: ImmutableArray<int>.Empty,
                resultKind: resultKind,
                type: objectType,
                hasErrors: hasErrors)
            { WasCompilerGenerated = true };
        }
        /// <summary>
        /// Bind the (implicit or explicit) constructor initializer of a constructor symbol.
        /// </summary>
        /// <param name="constructor">Constructor method.</param>
        /// <param name="diagnostics">Accumulates errors (e.g. access "this" in constructor initializer).</param>
        /// <param name="compilation">Used to retrieve binder.</param>
        /// <returns>A bound expression for the constructor initializer call.</returns>
        private static BoundExpression BindConstructorInitializer(MethodSymbol constructor, DiagnosticBag diagnostics, CSharpCompilation compilation)
        {
            // Note that the base type can be null if we're compiling System.Object in source.
            NamedTypeSymbol baseType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;
            CSharpSyntaxNode syntax = null;
            ArgumentListSyntax initializerArgumentListOpt = null;
            if ((object)sourceConstructor != null)
            {
                syntax = sourceConstructor.SyntaxNode;

                if (syntax.Kind == SyntaxKind.ConstructorDeclaration)
                {
                    var constructorSyntax = (ConstructorDeclarationSyntax)syntax;
                    if (constructorSyntax.Initializer != null)
                    {
                        initializerArgumentListOpt = constructorSyntax.Initializer.ArgumentList;
                    }

                    ErrorCode reportIfHavePrimaryCtor = ErrorCode.Void;

                    if (initializerArgumentListOpt == null || initializerArgumentListOpt.Parent.Kind != SyntaxKind.ThisConstructorInitializer)
                    {
                        reportIfHavePrimaryCtor = ErrorCode.ERR_InstanceCtorMustHaveThisInitializer;
                    }
                    else if (initializerArgumentListOpt.Arguments.Count == 0 && constructor.ContainingType.TypeKind == TypeKind.Struct)
                    {
                        // Based on C# Design Notes for Oct 21, 2013:
                        reportIfHavePrimaryCtor = ErrorCode.ERR_InstanceCtorCannotHaveDefaultThisInitializer;
                    }

                    if (reportIfHavePrimaryCtor != ErrorCode.Void)
                    {
                        var container = constructor.ContainingType as SourceMemberContainerTypeSymbol;

                        if ((object)container != null && (object)container.PrimaryCtor != null)
                        {
                            diagnostics.Add(reportIfHavePrimaryCtor, constructor.Locations[0]);
                        }
                    }
                }
                else 
                {
                    // Primary constuctor case.
                    Debug.Assert(syntax.Kind == SyntaxKind.ParameterList);
                    if (syntax.Parent.Kind == SyntaxKind.ClassDeclaration)
                    {
                        var classDecl = (ClassDeclarationSyntax)syntax.Parent;

                        if (classDecl.BaseList != null && classDecl.BaseList.Types.Count > 0)
                        {
                            TypeSyntax baseTypeSyntax = classDecl.BaseList.Types[0];
                            if (baseTypeSyntax.Kind == SyntaxKind.BaseClassWithArguments)
                            {
                                initializerArgumentListOpt = ((BaseClassWithArgumentsSyntax)baseTypeSyntax).ArgumentList;
                            }
                        }
                    }
                    else
            {
                        Debug.Assert(syntax.Parent.Kind == SyntaxKind.StructDeclaration);
                    }
                }
            }

            // The common case is that we have no constructor initializer and the type inherits directly from object.
            // Also, we might be trying to generate a constructor for an entirely compiler-generated class such
            // as a closure class; in that case it is vexing to try to find a suitable binder for the non-existing
            // constructor syntax so that we can do unnecessary overload resolution on the non-existing initializer!
            // Simply take the early out: bind directly to the parameterless object ctor rather than attempting
            // overload resolution.
            if (initializerArgumentListOpt == null && (object)baseType != null)
            {
                if (baseType.SpecialType == SpecialType.System_Object)
                {
                    return GenerateObjectConstructorInitializer(constructor, diagnostics);
                }
                else if (baseType.IsErrorType() || baseType.IsStatic)
                {
                    // If the base type is bad and there is no initializer then we can just bail.
                    // We have no expressions we need to analyze to report errors on.
                    return null;
                }
            }

            // Either our base type is not object, or we have an initializer syntax, or both. We're going to
            // need to do overload resolution on the set of constructors of the base type, either on
            // the provided initializer syntax, or on an implicit ": base()" syntax.

            // SPEC ERROR: The specification states that if you have the situation 
            // SPEC ERROR: class B { ... } class D1 : B {} then the default constructor
            // SPEC ERROR: generated for D1 must call an accessible *parameterless* constructor
            // SPEC ERROR: in B. However, it also states that if you have 
            // SPEC ERROR: class B { ... } class D2 : B { D2() {} }  or
            // SPEC ERROR: class B { ... } class D3 : B { D3() : base() {} }  then
            // SPEC ERROR: the compiler performs *overload resolution* to determine
            // SPEC ERROR: which accessible constructor of B is called. Since B might have
            // SPEC ERROR: a ctor with all optional parameters, overload resolution might
            // SPEC ERROR: succeed even if there is no parameterless constructor. This
            // SPEC ERROR: is unintentionally inconsistent, and the native compiler does not
            // SPEC ERROR: implement this behavior. Rather, we should say in the spec that
            // SPEC ERROR: if there is no ctor in D1, then a ctor is created for you exactly
            // SPEC ERROR: as though you'd said "D1() : base() {}". 
            // SPEC ERROR: This is what we now do in Roslyn.

            // Now, in order to do overload resolution, we're going to need a binder. There are
            // three possible situations:
            //
            // class D1 : B { }
            // class D2 : B { D2(int x) { } }
            // class D3 : B { D3(int x) : base(x) { } }
            //
            // In the first case the binder needs to be the binder associated with
            // the *body* of D1 because if the base class ctor is protected, we need
            // to be inside the body of a derived class in order for it to be in the
            // accessibility domain of the protected base class ctor.
            //
            // In the second case the binder could be the binder associated with 
            // the body of D2; since the implicit call to base() will have no arguments
            // there is no need to look up "x".
            // 
            // In the third case the binder must be the binder that knows about "x" 
            // because x is in scope.

            Binder outerBinder;

            if ((object)sourceConstructor == null)
            {
                // The constructor is implicit. We need to get the binder for the body
                // of the enclosing class. 
                CSharpSyntaxNode containerNode = constructor.GetNonNullSyntaxNode();
                SyntaxToken bodyToken;
                if (containerNode.Kind == SyntaxKind.ClassDeclaration)
                {
                    bodyToken = ((ClassDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else if (containerNode.Kind == SyntaxKind.StructDeclaration)
                {
                    bodyToken = ((StructDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else if (containerNode.Kind == SyntaxKind.EnumDeclaration)
                {
                    // We're not going to find any non-default ctors, but we'll look anyway.
                    bodyToken = ((EnumDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else
                {
                    Debug.Assert(false, "How did we get an implicit constructor added to something that is neither a class nor a struct?");
                    bodyToken = containerNode.GetFirstToken();
                }

                outerBinder = compilation.GetBinderFactory(containerNode.SyntaxTree).GetBinder(containerNode, bodyToken.Position);
            }
            else if (initializerArgumentListOpt == null)
            {
                // We have a ctor in source but no explicit constructor initializer.  We can't just use the binder for the
                // type containing the ctor because the ctor might be marked unsafe.  Use the binder for the parameter list
                // as an approximation - the extra symbols won't matter because there are no identifiers to bind.

                outerBinder = compilation.GetBinderFactory(sourceConstructor.SyntaxTree).GetBinder(syntax.Kind == SyntaxKind.ParameterList ? 
                                                                                                        syntax :
                                                                                                        ((ConstructorDeclarationSyntax)syntax).ParameterList);
            }
            else
            {
                outerBinder = compilation.GetBinderFactory(sourceConstructor.SyntaxTree).GetBinder(initializerArgumentListOpt);
            }

            //wrap in ConstructorInitializerBinder for appropriate errors
            Binder initializerBinder = outerBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructor);
            return initializerBinder.BindConstructorInitializer(initializerArgumentListOpt, constructor, diagnostics);
        }
        // NOTE: can return null if the method has no body.
        internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList<Imports> debugImports)
        {
            debugImports = null;

            BoundStatement constructorInitializer = null;
            BoundBlock body;

            var compilation = method.DeclaringCompilation;

            var sourceMethod = method as SourceMethodSymbol;
            if ((object)sourceMethod != null)
            {
                if (sourceMethod.IsExtern)
                {
                    if (sourceMethod.BlockSyntax == null)
                    {
                        // Generate warnings only if we are not generating ERR_ExternHasBody error
                        GenerateExternalMethodWarnings(sourceMethod, diagnostics);
                    }
                    return null;
                }
                else if (sourceMethod.IsParameterlessValueTypeConstructor(requireSynthesized: true))
                {
                    // No body for default struct constructor.
                    return null;
                }

                var blockSyntax = sourceMethod.BlockSyntax;
                if (blockSyntax != null)
                {
                var factory = compilation.GetBinderFactory(sourceMethod.SyntaxTree);
                var inMethodBinder = factory.GetBinder(blockSyntax);
                var binder = new ExecutableCodeBinder(blockSyntax, sourceMethod, inMethodBinder);
                body = binder.BindBlock(blockSyntax, diagnostics);
                if (generateDebugInfo)
                {
                    debugImports = binder.ImportsList;
                }
                if (inMethodBinder.IsDirectlyInIterator)
                {
                    foreach (var parameter in method.Parameters)
                    {
                        if (parameter.RefKind != RefKind.None)
                        {
                            diagnostics.Add(ErrorCode.ERR_BadIteratorArgType, parameter.Locations[0]);
                        }
                        else if (parameter.Type.IsUnsafe())
                        {
                            diagnostics.Add(ErrorCode.ERR_UnsafeIteratorArgType, parameter.Locations[0]);
                        }
                    }

                    if (sourceMethod.IsUnsafe && compilation.Options.AllowUnsafe) // Don't cascade
                    {
                        diagnostics.Add(ErrorCode.ERR_IllegalInnerUnsafe, sourceMethod.Locations[0]);
                    }

                    if (sourceMethod.IsVararg)
                    {
                        // error CS1636: __arglist is not allowed in the parameter list of iterators
                        diagnostics.Add(ErrorCode.ERR_VarargsIterator, sourceMethod.Locations[0]);
                    }
                    }
                }
                else // for [if (blockSyntax != null)]
                {
                    var property = sourceMethod.AssociatedSymbol as SourcePropertySymbol;
                    if ((object)property != null && property.IsAutoProperty)
                    {
                        return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod);
                }

                    if (sourceMethod.IsPrimaryCtor)
                    {
                        body = null;
            }
            else
            {
                        return null;
                    }
                }
            }
            else
            {
                //  synthesized methods should return their bound bodies 
                body = null;
            }

            // delegates have constructors but not constructor initializers
            if (method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType())
            {
                var initializerInvocation = BindConstructorInitializer(method, diagnostics, compilation);

                if (initializerInvocation != null)
                {
                    constructorInitializer = new BoundExpressionStatement(initializerInvocation.Syntax, initializerInvocation) { WasCompilerGenerated = true };
                    Debug.Assert(initializerInvocation.HasAnyErrors || constructorInitializer.IsConstructorInitializer(), "Please keep this bound node in sync with BoundNodeExtensions.IsConstructorInitializer.");
                }
            }

            var statements = ArrayBuilder<BoundStatement>.GetInstance();

            if (constructorInitializer != null)
            {
                statements.Add(constructorInitializer);
            }

            if ((object)sourceMethod != null && sourceMethod.IsPrimaryCtor && (object)((SourceMemberContainerTypeSymbol)sourceMethod.ContainingType).PrimaryCtor == (object)sourceMethod)
            {
                Debug.Assert(method.MethodKind == MethodKind.Constructor && !method.ContainingType.IsDelegateType());
                Debug.Assert(body == null);

                if (sourceMethod.ParameterCount > 0)
                {
                    var factory = new SyntheticBoundNodeFactory(sourceMethod, sourceMethod.SyntaxNode, compilationState, diagnostics);
                    factory.CurrentMethod = sourceMethod; 

                    foreach (var parameter in sourceMethod.Parameters)
                    {
                        FieldSymbol field = parameter.PrimaryConstructorParameterBackingField;

                        if ((object)field != null)
                        {
                            statements.Add(factory.Assignment(factory.Field(factory.This(), field),
                                                                   factory.Parameter(parameter)));
                        }
                    }
                }
            }

            if (body != null)
            {
                statements.Add(body);
            }

            CSharpSyntaxNode syntax = body != null ? body.Syntax : method.GetNonNullSyntaxNode();

            BoundBlock block;
            if (statements.Count == 1 && statements[0].Kind == ((body == null) ? BoundKind.Block : body.Kind))
            {
                // most common case - we just have a single block for the body.
                block = (BoundBlock)statements[0];
                statements.Free();
            }
            else
            {
                block = new BoundBlock(syntax, default(ImmutableArray<LocalSymbol>), statements.ToImmutableAndFree()) { WasCompilerGenerated = true };
            }

            return method.MethodKind == MethodKind.Destructor ? MethodBodySynthesizer.ConstructDestructorBody(syntax, method, block) : block;
        }
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol constructor)
        {
            Debug.Assert(!boundInitializers.IsDefault);

            var boundStatements = ArrayBuilder<BoundStatement>.GetInstance(boundInitializers.Length);

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                        break;

                    case BoundKind.InitializationScope:
                        var scope = (BoundInitializationScope)init;
                        var fieldInitializers = ArrayBuilder<BoundStatement>.GetInstance(scope.Initializers.Length);

                        foreach (BoundFieldInitializer fieldInitializer in scope.Initializers)
                        {
                            fieldInitializers.Add(RewriteFieldInitializer(fieldInitializer));
                        }

                        boundStatements.Add(new BoundBlock(scope.Syntax, scope.Locals, fieldInitializers.ToImmutableAndFree()) { WasCompilerGenerated = true });
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var stmtInit = (BoundGlobalStatementInitializer)init;

                        // the value of the last expression statement (if any) is stored to a ref parameter of the submission constructor:
                        if (constructor.IsSubmissionConstructor && i == boundInitializers.Length - 1 && stmtInit.Statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var syntax = stmtInit.Syntax;
                            var submissionResultVariable = new BoundParameter(syntax, constructor.Parameters[1]);
                            var expr = ((BoundExpressionStatement)stmtInit.Statement).Expression;

                            // The expression is converted to the submission result type when the initializer is bound, 
                            // so we just need to assign it to the out parameter:
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                boundStatements.Add(
                                    new BoundExpressionStatement(syntax,
                                        new BoundAssignmentOperator(syntax,
                                            submissionResultVariable,
                                            expr,
                                            expr.Type
                                        )
                                    ));

                                break;
                            }
                        }

                        boundStatements.Add(stmtInit.Statement);
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            Debug.Assert(boundStatements.Count == boundInitializers.Length);

            CSharpSyntaxNode listSyntax;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;
            if ((object)sourceConstructor != null)
            {
                listSyntax = sourceConstructor.SyntaxNode;
            }
            else
            {
                listSyntax = constructor.GetNonNullSyntaxNode();
            }

            return new BoundTypeOrInstanceInitializers(listSyntax, boundStatements.ToImmutableAndFree());
        }
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol method, TypeSymbol submissionResultTypeOpt)
        {
            Debug.Assert(!boundInitializers.IsDefault);
            Debug.Assert(method.IsSubmissionInitializer == ((object)submissionResultTypeOpt != null));

            var boundStatements = ArrayBuilder<BoundStatement>.GetInstance(boundInitializers.Length);
            BoundExpression submissionResult = null;

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var statement = ((BoundGlobalStatementInitializer)init).Statement;
                        // The value of the last expression statement (if any) is returned from the submission initializer.
                        if ((object)submissionResultTypeOpt != null &&
                            i == boundInitializers.Length - 1 &&
                            statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var expr = ((BoundExpressionStatement)statement).Expression;
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                submissionResult = expr;
                                break;
                            }
                        }
                        boundStatements.Add(statement);
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            var sourceMethod = method as SourceMethodSymbol;
            var syntax = ((object)sourceMethod != null) ? sourceMethod.SyntaxNode : method.GetNonNullSyntaxNode();

            if ((object)submissionResultTypeOpt != null)
            {
                if (submissionResult == null)
                {
                    // Return null if submission does not have a trailing expression.
                    Debug.Assert(submissionResultTypeOpt.IsReferenceType);
                    submissionResult = new BoundLiteral(syntax, ConstantValue.Null, submissionResultTypeOpt);
                }

                Debug.Assert((object)submissionResult.Type != null);
                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());
        }
Beispiel #8
0
        internal static BoundStatementList Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol constructor)
        {
            Debug.Assert(!boundInitializers.IsDefault);

            var boundStatements = new BoundStatement[boundInitializers.Length];
            for (int i = 0; i < boundStatements.Length; i++)
            {
                var init = boundInitializers[i];
                var syntax = init.Syntax;
                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        var fieldInit = (BoundFieldInitializer)init;

                        var boundReceiver = fieldInit.Field.IsStatic ? null :
                            new BoundThisReference(syntax, fieldInit.Field.ContainingType);

                        // Mark this as CompilerGenerated so that the local rewriter doesn't add a sequence point.
                        boundStatements[i] =
                            new BoundExpressionStatement(syntax,
                                new BoundAssignmentOperator(syntax,
                                    new BoundFieldAccess(syntax,
                                        boundReceiver,
                                        fieldInit.Field,
                                        constantValueOpt: null),
                                    fieldInit.InitialValue,
                                    fieldInit.Field.Type)
                        { WasCompilerGenerated = true })
                        { WasCompilerGenerated = true };

                        Debug.Assert(syntax is ExpressionSyntax); // Should be the initial value.
                        Debug.Assert(syntax.Parent.Kind == SyntaxKind.EqualsValueClause);
                        Debug.Assert(syntax.Parent.Parent.Kind == SyntaxKind.VariableDeclarator);
                        Debug.Assert(syntax.Parent.Parent.Parent.Kind == SyntaxKind.VariableDeclaration);

                        var declaratorSyntax = (VariableDeclaratorSyntax)syntax.Parent.Parent;
                        boundStatements[i] = LocalRewriter.AddSequencePoint(declaratorSyntax, boundStatements[i]);
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var stmtInit = (BoundGlobalStatementInitializer)init;

                        // the value of the last expression statement (if any) is stored to a ref parameter of the submission constructor:
                        if (constructor.IsSubmissionConstructor && i == boundStatements.Length - 1 && stmtInit.Statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var submissionResultVariable = new BoundParameter(syntax, constructor.Parameters[1]);
                            var expr = ((BoundExpressionStatement)stmtInit.Statement).Expression;

                            // The expression is converted to the submission result type when the initializer is bound, 
                            // so we just need to assign it to the out parameter:
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                boundStatements[i] =
                                    new BoundExpressionStatement(syntax,
                                        new BoundAssignmentOperator(syntax,
                                            submissionResultVariable,
                                            expr,
                                            expr.Type
                                        )
                                    );

                                break;
                            }
                        }

                        boundStatements[i] = stmtInit.Statement;
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            CSharpSyntaxNode listSyntax;

            SourceMethodSymbol sourceConstructor = constructor as SourceMethodSymbol;
            if ((object)sourceConstructor != null)
            {
                listSyntax = sourceConstructor.SyntaxNode;
            }
            else
            {
                listSyntax = constructor.GetNonNullSyntaxNode();
            }

            return new BoundStatementList(listSyntax, boundStatements.AsImmutableOrNull());
        }