/// <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; }
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()); }
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()); }