Ejemplo n.º 1
0
        internal static BoundStatement RewriteXSharpMethod(MethodSymbol method,
                                                           BoundStatement body,
                                                           int methodOrdinal,
                                                           TypeCompilationState compilationState,
                                                           DiagnosticBag diagnostics)
        {
            switch (method.Name)
            {
            case XSharpSpecialNames.AppInit:
                body = LocalRewriter.RewriteAppInit(method, body, diagnostics);
                break;

            case XSharpSpecialNames.AppExit:
                body = LocalRewriter.RewriteAppExit(method, body, diagnostics);
                break;

            case XSharpSpecialNames.ExitProc:
                body = LocalRewriter.RewriteExit(method, body, diagnostics);
                break;

            case ReservedNames.RunInitProcs:
                body = LocalRewriter.RewriteRunInitProc(method, body, diagnostics);
                break;
            }
            switch (method.MethodKind)
            {
            case MethodKind.PropertyGet:
            case MethodKind.PropertySet:
                var node = method.GetNonNullSyntaxNode();
                if (node.XGenerated)
                {
                    if (body is BoundBlock oldbody)
                    {
                        var newbody = new BoundBlock(oldbody.Syntax, oldbody.Locals, oldbody.Statements, oldbody.HasErrors)
                        {
                            WasCompilerGenerated = true
                        };
                        body = newbody;
                    }
                }
                break;
            }

            var xnode = method.GetNonNullSyntaxNode().XNode as XSharpParserRuleContext;

            if (xnode is XSharpParser.ClsmethodContext cmc)
            {
                xnode = cmc.Member;
            }
            else if (xnode is XSharpParser.FoxclsmethodContext fmc)
            {
                xnode = fmc.Member;
            }
            if (xnode is XSharpParser.IEntityContext iec)
            {
                body = LocalRewriter.RemoveUnusedVars(iec.Data, body, diagnostics);
            }

            return(body);
        }
Ejemplo n.º 2
0
        /// <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.IsTaskReturningAsync(compilation))
            {
                // 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, RefKind.None, 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);
        }
Ejemplo n.º 3
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 SourceMemberMethodSymbol;
            var syntax       =
                ((object)sourceMethod != null)
                    ? sourceMethod.SyntaxNode
                    : method.GetNonNullSyntaxNode();

            return(new BoundTypeOrInstanceInitializers(
                       syntax,
                       boundInitializers.SelectAsArray(RewriteInitializersAsStatements)
                       ));
        }
Ejemplo n.º 4
0
        public static void VerifyMethodThrowsWithBase(MethodSymbol method, MethodSymbol baseMethod, DiagnosticBag diagnostics)
        {
            if (method.HasThrows && baseMethod != null)
            {
                var syntax = (MethodDeclarationSyntax)method.GetNonNullSyntaxNode();
                if (!baseMethod.HasThrows)
                {
                    diagnostics.Add(ErrorCode.ERR_MissingThrowsOnBaseMethod, syntax.Identifier.GetLocation());
                }
                else
                {
                    // TODO: Should we use it?
                    HashSet <DiagnosticInfo> unused = null;
                    int throwTypeIndex = 0;
                    foreach (var throwType in method.ThrowsList)
                    {
                        bool isDeclaredByBase = false;
                        foreach (var baseThrowType in baseMethod.ThrowsList)
                        {
                            if (throwType.IsEqualToOrDerivedFrom(baseThrowType, TypeCompareKind.ConsiderEverything, ref unused))
                            {
                                isDeclaredByBase = true;
                                break;
                            }
                        }

                        if (!isDeclaredByBase)
                        {
                            diagnostics.Add(ErrorCode.ERR_ThrowsNotDeclaredByBaseMethod, syntax.ThrowsList.Types[throwTypeIndex].GetLocation(), throwType.ToDisplayString());
                        }

                        throwTypeIndex++;
                    }
                }
            }
        }
Ejemplo n.º 5
0
        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.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()));
        }
Ejemplo n.º 6
0
        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
            });
        }
Ejemplo n.º 7
0
        /// <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));
        }
Ejemplo n.º 8
0
        // 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);
        }
Ejemplo n.º 9
0
        public static BoundBlock Rewrite(
            MethodSymbol method,
            BoundBlock block,
            TypeCompilationState compilationState,
            BindingDiagnosticBag 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().Diagnostics.Length;
#endif
            var compilation = method.DeclaringCompilation;

            if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation))
            {
                ImmutableArray <FieldSymbol> implicitlyInitializedFields = default;
                bool needsImplicitReturn = true;
                // we don't analyze synthesized void methods.
                if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer) ||
                    Analyze(compilation, method, block, diagnostics.DiagnosticBag, out needsImplicitReturn, out implicitlyInitializedFields))
                {
                    if (!implicitlyInitializedFields.IsDefault)
                    {
                        Debug.Assert(!implicitlyInitializedFields.IsEmpty);
                        block = PrependImplicitInitializations(block, method, implicitlyInitializedFields, compilationState, diagnostics);
                    }
                    if (needsImplicitReturn)
                    {
                        block = AppendImplicitReturn(block, method, originalBodyNested);
                    }
                }
            }
            else if (Analyze(compilation, method, block, diagnostics.DiagnosticBag, out var needsImplicitReturn, out var unusedImplicitlyInitializedFields))
            {
                Debug.Assert(unusedImplicitlyInitializedFields.IsDefault);
                Debug.Assert(needsImplicitReturn);
                // 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.IsVoidType());

                    var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType);
                    var newStatements      = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression, @checked: false));
                    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.
                    IEnumerable <Diagnostic> getErrorsOnly(IEnumerable <Diagnostic> diags) => diags.Where(d => d.Severity == DiagnosticSeverity.Error);

                    var flowAnalysisDiagnostics = DiagnosticBag.GetInstance();
                    Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics, needsImplicitReturn: out _, out unusedImplicitlyInitializedFields));
                    Debug.Assert(unusedImplicitlyInitializedFields.IsDefault);
                    // Ignore warnings since flow analysis reports nullability mismatches.
                    Debug.Assert(getErrorsOnly(flowAnalysisDiagnostics.ToReadOnly()).SequenceEqual(getErrorsOnly(diagnostics.ToReadOnly().Diagnostics.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);
        }
Ejemplo n.º 10
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()));
        }
Ejemplo n.º 11
0
        //TODO: it might be nice to make this a static method on Compiler
        private void CompileMethod(
            MethodSymbol methodSymbol,
            ref ProcessedFieldInitializers processedInitializers,
            SynthesizedSubmissionFields previousSubmissionFields,
            TypeCompilationState compilationState)
        {
            cancellationToken.ThrowIfCancellationRequested();
            SourceMethodSymbol sourceMethod = methodSymbol as SourceMethodSymbol;

            if (methodSymbol.IsAbstract)
            {
                if ((object)sourceMethod != null)
                {
                    bool diagsWritten;
                    sourceMethod.SetDiagnostics(ImmutableArray <Diagnostic> .Empty, out diagsWritten);
                    if (diagsWritten && !methodSymbol.IsImplicitlyDeclared && compilation.EventQueue != null)
                    {
                        compilation.SymbolDeclaredEvent(methodSymbol);
                    }
                }

                return;
            }

            // get cached diagnostics if not building and we have 'em
            bool calculateDiagnosticsOnly = moduleBeingBuilt == null;

            if (calculateDiagnosticsOnly && ((object)sourceMethod != null))
            {
                var cachedDiagnostics = sourceMethod.Diagnostics;

                if (!cachedDiagnostics.IsDefault)
                {
                    this.diagnostics.AddRange(cachedDiagnostics);
                    return;
                }
            }

            ConsList <Imports> oldDebugImports = compilationState.CurrentDebugImports;

            // In order to avoid generating code for methods with errors, we create a diagnostic bag just for this method.
            DiagnosticBag diagsForCurrentMethod = DiagnosticBag.GetInstance();

            try
            {
                bool       includeInitializersInBody;
                BoundBlock body;

                // if synthesized method returns its body in lowered form
                if (methodSymbol.SynthesizesLoweredBoundBody)
                {
                    if (moduleBeingBuilt != null)
                    {
                        methodSymbol.GenerateMethodBody(compilationState, diagsForCurrentMethod);
                        this.diagnostics.AddRange(diagsForCurrentMethod);
                    }

                    return;
                }

                //EDMAURER initializers that have been analyzed but not yet lowered.
                BoundStatementList analyzedInitializers = null;

                ConsList <Imports> debugImports;

                if (methodSymbol.IsScriptConstructor)
                {
                    // rewrite top-level statements and script variable declarations to a list of statements and assignments, respectively:
                    BoundStatementList initializerStatements = InitializerRewriter.Rewrite(processedInitializers.BoundInitializers, methodSymbol);

                    // the lowered script initializers should not be treated as initializers anymore but as a method body:
                    body = new BoundBlock(initializerStatements.Syntax, ImmutableArray <LocalSymbol> .Empty, initializerStatements.Statements)
                    {
                        WasCompilerGenerated = true
                    };
                    includeInitializersInBody = false;

                    debugImports = null;
                }
                else
                {
                    // do not emit initializers if we are invoking another constructor of this class:
                    includeInitializersInBody = !processedInitializers.BoundInitializers.IsDefaultOrEmpty && !HasThisConstructorInitializer(methodSymbol);

                    // lower initializers just once. the lowered tree will be reused when emitting all constructors
                    // with field initializers. Once lowered, these initializers will be stashed in processedInitializers.LoweredInitializers
                    // (see later in this method). Don't bother lowering _now_ if this particular ctor won't have the initializers
                    // appended to its body.
                    if (includeInitializersInBody && processedInitializers.LoweredInitializers == null)
                    {
                        analyzedInitializers            = InitializerRewriter.Rewrite(processedInitializers.BoundInitializers, methodSymbol);
                        processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors;

                        // These analyses check for diagnostics in lambdas.
                        // Control flow analysis and implicit return insertion are unnecessary.
                        DataFlowPass.Analyze(compilation, methodSymbol, analyzedInitializers, diagsForCurrentMethod, requireOutParamsAssigned: false);
                        DiagnosticsPass.IssueDiagnostics(compilation, analyzedInitializers, diagsForCurrentMethod, methodSymbol);
                    }

                    body = Compiler.BindMethodBody(methodSymbol, diagsForCurrentMethod, this.generateDebugInfo, out debugImports);
                }

#if DEBUG
                // If the method is a synthesized static or instance constructor, then debugImports will be null and we will use the value
                // from the first field initializer.
                if (this.generateDebugInfo)
                {
                    if ((methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) && methodSymbol.IsImplicitlyDeclared)
                    {
                        // There was no body to bind, so we didn't get anything from Compiler.BindMethodBody.
                        Debug.Assert(debugImports == null);
                        // Either there were no field initializers or we grabbed debug imports from the first one.
                        Debug.Assert(processedInitializers.BoundInitializers.IsDefaultOrEmpty || processedInitializers.FirstDebugImports != null);
                    }
                }
#endif

                debugImports = debugImports ?? processedInitializers.FirstDebugImports;

                // Associate these debug imports with all methods generated from this one.
                compilationState.CurrentDebugImports = debugImports;

                if (body != null && methodSymbol is SourceMethodSymbol)
                {
                    // TODO: Do we need to issue warnings for non-SourceMethodSymbol methods, like synthesized ctors?
                    DiagnosticsPass.IssueDiagnostics(compilation, body, diagsForCurrentMethod, methodSymbol);
                }

                BoundBlock flowAnalyzedBody = null;
                if (body != null)
                {
                    flowAnalyzedBody = FlowAnalysisPass.Rewrite(methodSymbol, body, diagsForCurrentMethod);
                }

                bool hasErrors = hasDeclarationErrors || diagsForCurrentMethod.HasAnyErrors() || processedInitializers.HasErrors;

                // Record whether or not the bound tree for the lowered method body (including any initializers) contained any
                // errors (note: errors, not diagnostics).
                SetGlobalErrorIfTrue(hasErrors);

                bool diagsWritten      = false;
                var  actualDiagnostics = diagsForCurrentMethod.ToReadOnly();
                if (sourceMethod != null)
                {
                    actualDiagnostics = sourceMethod.SetDiagnostics(actualDiagnostics, out diagsWritten);
                }
                if (diagsWritten && !methodSymbol.IsImplicitlyDeclared && compilation.EventQueue != null)
                {
                    var lazySemanticModel = body == null ? null : new Lazy <SemanticModel>(() =>
                    {
                        var syntax        = body.Syntax;
                        var semanticModel = (CSharpSemanticModel)compilation.GetSemanticModel(syntax.SyntaxTree);
                        var memberModel   = semanticModel.GetMemberModel(syntax);
                        if (memberModel != null)
                        {
                            memberModel.AddBoundTreeForStandaloneSyntax(syntax, body);
                        }
                        return(semanticModel);
                    });
                    compilation.EventQueue.Enqueue(new CompilationEvent.SymbolDeclared(compilation, methodSymbol, lazySemanticModel));
                }

                // Don't lower if we're not emitting or if there were errors.
                // Methods that had binding errors are considered too broken to be lowered reliably.
                if (calculateDiagnosticsOnly || hasErrors)
                {
                    this.diagnostics.AddRange(actualDiagnostics);
                    return;
                }

                // ############################
                // LOWERING AND EMIT
                // Any errors generated below here are considered Emit diagnostics
                // and will not be reported to callers Compilation.GetDiagnostics()

                BoundStatement loweredBody = (flowAnalyzedBody == null) ? null :
                                             Compiler.LowerStatement(this.generateDebugInfo, methodSymbol, flowAnalyzedBody, previousSubmissionFields, compilationState, diagsForCurrentMethod);

                bool hasBody = loweredBody != null;

                hasErrors = hasErrors || (hasBody && loweredBody.HasErrors) || diagsForCurrentMethod.HasAnyErrors();
                SetGlobalErrorIfTrue(hasErrors);

                // don't emit if the resulting method would contain initializers with errors
                if (!hasErrors && (hasBody || includeInitializersInBody))
                {
                    // Fields must be initialized before constructor initializer (which is the first statement of the analyzed body, if specified),
                    // so that the initialization occurs before any method overridden by the declaring class can be invoked from the base constructor
                    // and access the fields.

                    ImmutableArray <BoundStatement> boundStatements;

                    if (methodSymbol.IsScriptConstructor)
                    {
                        boundStatements = MethodBodySynthesizer.ConstructScriptConstructorBody(loweredBody, methodSymbol, previousSubmissionFields, compilation);
                    }
                    else
                    {
                        boundStatements = ImmutableArray <BoundStatement> .Empty;

                        if (analyzedInitializers != null)
                        {
                            processedInitializers.LoweredInitializers = (BoundStatementList)Compiler.LowerStatement(
                                this.generateDebugInfo,
                                methodSymbol,
                                analyzedInitializers,
                                previousSubmissionFields,
                                compilationState,
                                diagsForCurrentMethod);

                            Debug.Assert(!hasErrors);
                            hasErrors = processedInitializers.LoweredInitializers.HasAnyErrors || diagsForCurrentMethod.HasAnyErrors();
                            SetGlobalErrorIfTrue(hasErrors);

                            if (hasErrors)
                            {
                                this.diagnostics.AddRange(diagsForCurrentMethod);
                                return;
                            }
                        }

                        // initializers for global code have already been included in the body
                        if (includeInitializersInBody)
                        {
                            //TODO: rewrite any BoundThis and BoundBase nodes in the initializers to have the correct ThisParameter symbol
                            if (compilation.Options.Optimize)
                            {
                                // TODO: this part may conflict with InitializerRewriter.Rewrite in how it handles
                                //       the first field initializer (see 'if (i == 0)'...) which seems suspicious
                                ArrayBuilder <BoundStatement> statements = ArrayBuilder <BoundStatement> .GetInstance();

                                statements.AddRange(boundStatements);
                                bool anyNonDefault = false;

                                foreach (var initializer in processedInitializers.LoweredInitializers.Statements)
                                {
                                    if (ShouldOptimizeOutInitializer(initializer))
                                    {
                                        if (methodSymbol.IsStatic)
                                        {
                                            // NOTE: Dev11 removes static initializers if ONLY all of them are optimized out
                                            statements.Add(initializer);
                                        }
                                    }
                                    else
                                    {
                                        statements.Add(initializer);
                                        anyNonDefault = true;
                                    }
                                }

                                if (anyNonDefault)
                                {
                                    boundStatements = statements.ToImmutableAndFree();
                                }
                                else
                                {
                                    statements.Free();
                                }
                            }
                            else
                            {
                                boundStatements = boundStatements.Concat(processedInitializers.LoweredInitializers.Statements);
                            }
                        }

                        if (hasBody)
                        {
                            boundStatements = boundStatements.Concat(ImmutableArray.Create(loweredBody));
                        }
                    }

                    CSharpSyntaxNode syntax = methodSymbol.GetNonNullSyntaxNode();

                    var boundBody = BoundStatementList.Synthesized(syntax, boundStatements);

                    var emittedBody = Compiler.GenerateMethodBody(
                        compilationState,
                        methodSymbol,
                        boundBody,
                        diagsForCurrentMethod,
                        optimize,
                        debugDocumentProvider,
                        GetNamespaceScopes(methodSymbol, debugImports));

                    moduleBeingBuilt.SetMethodBody(methodSymbol, emittedBody);
                }

                this.diagnostics.AddRange(diagsForCurrentMethod);
            }
            finally
            {
                diagsForCurrentMethod.Free();
                compilationState.CurrentDebugImports = oldDebugImports;
            }
        }
Ejemplo n.º 12
0
        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()));
        }