internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.ArrowExpressionClause: return(binder.BindExpressionBodyAsBlock((ArrowExpressionClauseSyntax)node, diagnostics)); case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: return(binder.BindConstructorInitializer((ConstructorInitializerSyntax)node, diagnostics)); case SyntaxKind.MethodDeclaration: case SyntaxKind.ConversionOperatorDeclaration: case SyntaxKind.OperatorDeclaration: case SyntaxKind.ConstructorDeclaration: case SyntaxKind.DestructorDeclaration: case SyntaxKind.GetAccessorDeclaration: case SyntaxKind.SetAccessorDeclaration: case SyntaxKind.AddAccessorDeclaration: case SyntaxKind.RemoveAccessorDeclaration: return(binder.BindMethodBody(node, diagnostics)); } return(base.Bind(binder, node, diagnostics)); }
internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics) { EqualsValueClauseSyntax equalsValue = null; switch (node.Kind()) { case SyntaxKind.EqualsValueClause: equalsValue = (EqualsValueClauseSyntax)node; break; case SyntaxKind.VariableDeclarator: equalsValue = ((VariableDeclaratorSyntax)node).Initializer; break; case SyntaxKind.PropertyDeclaration: equalsValue = ((PropertyDeclarationSyntax)node).Initializer; break; case SyntaxKind.Parameter: equalsValue = ((ParameterSyntax)node).Default; break; case SyntaxKind.EnumMemberDeclaration: equalsValue = ((EnumMemberDeclarationSyntax)node).EqualsValue; break; case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: return(binder.BindConstructorInitializer(((ConstructorInitializerSyntax)node).ArgumentList, (MethodSymbol)MemberSymbol, diagnostics)); case SyntaxKind.ArgumentList: return(binder.BindConstructorInitializer((ArgumentListSyntax)node, (MethodSymbol)MemberSymbol, diagnostics)); } if (equalsValue != null) { return(BindEqualsValue(binder, equalsValue, diagnostics)); } return(base.Bind(binder, node, diagnostics)); }
internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics) { EqualsValueClauseSyntax equalsValue = null; switch (node.Kind()) { case SyntaxKind.EqualsValueClause: equalsValue = (EqualsValueClauseSyntax)node; break; case SyntaxKind.VariableDeclarator: equalsValue = ((VariableDeclaratorSyntax)node).Initializer; break; case SyntaxKind.PropertyDeclaration: equalsValue = ((PropertyDeclarationSyntax)node).Initializer; break; case SyntaxKind.Parameter: equalsValue = ((ParameterSyntax)node).Default; break; case SyntaxKind.EnumMemberDeclaration: equalsValue = ((EnumMemberDeclarationSyntax)node).EqualsValue; break; case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: return binder.BindConstructorInitializer(((ConstructorInitializerSyntax)node).ArgumentList, (MethodSymbol)MemberSymbol, diagnostics); case SyntaxKind.ArgumentList: return binder.BindConstructorInitializer((ArgumentListSyntax)node, (MethodSymbol)MemberSymbol, diagnostics); } if (equalsValue != null) { return BindEqualsValue(binder, equalsValue, diagnostics); } return base.Bind(binder, node, diagnostics); }
/// <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)); }