/// <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> /// <returns>the rewritten block for the method (with a return statement possibly inserted)</returns> public static BoundBlock Rewrite( MethodSymbol method, BoundBlock block, DiagnosticBag diagnostics) { var compilation = method.DeclaringCompilation; SourceMethodSymbol sourceMethod = method as SourceMethodSymbol; if (method.ReturnsVoid || (object)method.IteratorElementType != null || (method.IsAsync && compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) == method.ReturnType)) { if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics)) { // we don't analyze synthesized void methods. block = AppendImplicitReturn(block, method, (object)sourceMethod != null ? sourceMethod.BlockSyntax : null); } } 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); // If there's more than one location, then the method is partial and we // have already reported a non-void partial method error. if (method.Locations.Length == 1) { diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method); } } return(block); }
public void Write(MethodSymbols symbols) { var method = new SourceMethodSymbol(symbols); var file = GetSourceFile(symbols.Instructions [0].SequencePoint.Document); var builder = writer.OpenMethod(file.CompilationUnit, 0, method); var count = symbols.Instructions.Count; for (int i = 0; i < count; i++) { var instruction = symbols.Instructions [i]; var sequence_point = instruction.SequencePoint; builder.MarkSequencePoint( instruction.Offset, GetSourceFile(sequence_point.Document).CompilationUnit.SourceFile, sequence_point.StartLine, sequence_point.EndLine, false); } if (symbols.HasVariables) { AddVariables(symbols.Variables); } writer.CloseMethod(); }
private void HandleReturn() { builder.MarkLabel(ReturnLabel); Debug.Assert(method.ReturnsVoid == (returnTemp == null)); // in debug mode user could set a breakpoint on the last "}" of the method and // expect to hit it before exiting the method // we do it by rewriting all returns into a jump to an Exit label // and mark the Exit sequence with sequence point for the span of the last "}" BlockSyntax blockSyntax = null; SourceMethodSymbol sourceMethod = method as SourceMethodSymbol; if ((object)sourceMethod != null && (object)sourceMethod.IteratorElementType == null) { blockSyntax = sourceMethod.BlockSyntax; } if (blockSyntax != null && this.emitSequencePoints) { EmitSequencePoint(block.SyntaxTree ?? sourceMethod.SyntaxTree, blockSyntax.CloseBraceToken.Span); } if (returnTemp != null) { builder.EmitLocalLoad(LazyReturnTemp); builder.EmitRet(false); } else { builder.EmitRet(true); } indirectReturnState = IndirectReturnState.Emitted; }
/// <summary> /// Construct a body for an auto-property accessor (updating or returning the backing field). /// </summary> internal static BoundBlock ConstructAutoPropertyAccessorBody(SourceMethodSymbol accessor) { Debug.Assert(accessor.MethodKind == MethodKind.PropertyGet || accessor.MethodKind == MethodKind.PropertySet); var property = (SourcePropertySymbol)accessor.AssociatedSymbol; CSharpSyntaxNode syntax = property.CSharpSyntaxNode; BoundExpression thisReference = null; if (!accessor.IsStatic) { var thisSymbol = accessor.ThisParameter; thisReference = new BoundThisReference(syntax, thisSymbol.Type) { WasCompilerGenerated = true }; } var field = property.BackingField; var fieldAccess = new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }; BoundStatement statement; if (accessor.MethodKind == MethodKind.PropertyGet) { statement = new BoundReturnStatement(syntax, RefKind.None, fieldAccess) { WasCompilerGenerated = true }; } else { Debug.Assert(accessor.MethodKind == MethodKind.PropertySet); var parameter = accessor.Parameters[0]; statement = new BoundExpressionStatement( syntax, new BoundAssignmentOperator( syntax, fieldAccess, new BoundParameter(syntax, parameter) { WasCompilerGenerated = true }, property.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; } statement = new BoundSequencePoint(accessor.SyntaxNode, statement) { WasCompilerGenerated = true }; return(BoundBlock.SynthesizedNoLocals(syntax, statement)); }
internal static ImmutableArray <SyntaxNode> GetDeclarators(SourceMethodSymbol method) { var builder = ArrayBuilder <SyntaxNode> .GetInstance(); var visitor = new LocalVariableDeclaratorsCollector(builder); visitor.Visit(method.BodySyntax); return(builder.ToImmutableAndFree()); }
public static ImmutableMap <SyntaxNode, BlockBaseBinderContext> Build(SourceMethodSymbol method) { // UNDONE: partial methods var builder = new LocalBinderBuilder(method); builder.Visit( method.BlockSyntax, method.ParameterBinderContext); return(builder.map); }
private static void GenerateExternalMethodWarnings(SourceMethodSymbol methodSymbol, DiagnosticBag diagnostics) { if (methodSymbol.GetAttributes().IsEmpty&& !methodSymbol.ContainingType.IsComImport) { // external method with no attributes var errorCode = (methodSymbol.MethodKind == MethodKind.Constructor || methodSymbol.MethodKind == MethodKind.StaticConstructor) ? ErrorCode.WRN_ExternCtorNoImplementation : ErrorCode.WRN_ExternMethodNoImplementation; diagnostics.Add(errorCode, methodSymbol.Locations[0], methodSymbol); } }
private static bool MethodHasExplicitBlock(MethodSymbol method) { SourceMethodSymbol asSourceMethod = method.OriginalDefinition as SourceMethodSymbol; if ((object)asSourceMethod != null) { return(asSourceMethod.BodySyntax is BlockSyntax); } return(false); }
public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { ExecutableCodeBinder.ValidateIteratorMethod(_compilation, node.Symbol, _diagnostics); var outerLocalFunction = _staticLocalOrAnonymousFunction; if (node.Symbol.IsStatic) { _staticLocalOrAnonymousFunction = node.Symbol; } var result = base.VisitLocalFunctionStatement(node); _staticLocalOrAnonymousFunction = outerLocalFunction; return(result); }
/// <summary> /// Returns true if the method is a constructor and has a this() constructor initializer. /// </summary> private static bool HasThisConstructorInitializer(MethodSymbol method) { if ((object)method != null && method.MethodKind == MethodKind.Constructor) { SourceMethodSymbol sourceMethod = method as SourceMethodSymbol; if ((object)sourceMethod != null) { ConstructorDeclarationSyntax constructorSyntax = sourceMethod.SyntaxNode as ConstructorDeclarationSyntax; if (constructorSyntax != null) { ConstructorInitializerSyntax initializerSyntax = constructorSyntax.Initializer; if (initializerSyntax != null) { return(initializerSyntax.Kind == SyntaxKind.ThisConstructorInitializer); } } } } return(false); }
private AsyncRewriter( BoundStatement body, SourceMethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics) : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) { try { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { diagnostics.Add(ex.Diagnostic); _constructedSuccessfully = false; } _methodOrdinal = methodOrdinal; }
public void Write(MethodSymbols symbols) { var method = new SourceMethodSymbol (symbols); var file = GetSourceFile (symbols.Instructions [0].SequencePoint.Document); var builder = writer.OpenMethod (file.CompilationUnit, 0, method); var count = symbols.Instructions.Count; for (int i = 0; i < count; i++) { var instruction = symbols.Instructions [i]; var sequence_point = instruction.SequencePoint; builder.MarkSequencePoint ( instruction.Offset, GetSourceFile (sequence_point.Document).CompilationUnit.SourceFile, sequence_point.StartLine, sequence_point.EndLine, false); } if (symbols.HasVariables) AddVariables (symbols.Variables); writer.CloseMethod (); }
internal FakeMemberSemanticModel(Compilation compilation, SyntaxNode root, SourceMethodSymbol method, Binder rootBinder, ImmutableMap <SyntaxNode, Binder> map) : base(compilation, root, method) { this.rootBinder = rootBinder; this.map = map; }
public void Write(MethodSymbols symbols) { var method = new SourceMethodSymbol (symbols); var file = GetSourceFile (symbols.Document); var builder = writer.OpenMethod (file.CompilationUnit, 0, method); var count = symbols.Offsets.Length; for (int i = 0; i < count; i++) builder.MarkSequencePoint ( symbols.Offsets [i], file.CompilationUnit.SourceFile, symbols.StartRows [i], symbols.StartColumns [i], false); if (symbols.HasVariables) AddVariables (symbols.Variables); writer.CloseMethod (); }
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())); }
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())); }
private LocalBinderBuilder(SourceMethodSymbol method) { this.map = ImmutableMap <SyntaxNode, BlockBaseBinderContext> .Empty; this.method = method; }
//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; } }
internal MethodBodyBindings(SourceMethodSymbol methodSymbol) { this.methodSymbol = methodSymbol; }
public override BoundNode VisitLambda(BoundLambda node) { if (_inExpressionLambda) { var lambda = node.Symbol; foreach (var p in lambda.Parameters) { if (p.RefKind != RefKind.None && p.Locations.Length != 0) { _diagnostics.Add(ErrorCode.ERR_ByRefParameterInExpressionTree, p.Locations[0]); } if (p.TypeWithAnnotations.IsRestrictedType()) { _diagnostics.Add(ErrorCode.ERR_ExpressionTreeCantContainRefStruct, p.Locations[0], p.Type.Name); } } switch (node.Syntax.Kind()) { case SyntaxKind.ParenthesizedLambdaExpression: { var lambdaSyntax = (ParenthesizedLambdaExpressionSyntax)node.Syntax; if (lambdaSyntax.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword) { Error(ErrorCode.ERR_BadAsyncExpressionTree, node); } else if (lambdaSyntax.Body.Kind() == SyntaxKind.Block) { Error(ErrorCode.ERR_StatementLambdaToExpressionTree, node); } else if (lambdaSyntax.Body.Kind() == SyntaxKind.RefExpression) { Error(ErrorCode.ERR_BadRefReturnExpressionTree, node); } } break; case SyntaxKind.SimpleLambdaExpression: { var lambdaSyntax = (SimpleLambdaExpressionSyntax)node.Syntax; if (lambdaSyntax.AsyncKeyword.Kind() == SyntaxKind.AsyncKeyword) { Error(ErrorCode.ERR_BadAsyncExpressionTree, node); } else if (lambdaSyntax.Body.Kind() == SyntaxKind.Block) { Error(ErrorCode.ERR_StatementLambdaToExpressionTree, node); } else if (lambdaSyntax.Body.Kind() == SyntaxKind.RefExpression) { Error(ErrorCode.ERR_BadRefReturnExpressionTree, node); } } break; case SyntaxKind.AnonymousMethodExpression: Error(ErrorCode.ERR_ExpressionTreeContainsAnonymousMethod, node); break; default: // other syntax forms arise from query expressions, and always result from implied expression-lambda-like forms break; } } var outerLocalFunction = _staticLocalOrAnonymousFunction; if (node.Symbol.IsStatic) { _staticLocalOrAnonymousFunction = node.Symbol; } var result = base.VisitLambda(node); _staticLocalOrAnonymousFunction = outerLocalFunction; return(result); }
internal FakeMemberSemanticModel(Compilation compilation, SyntaxNode root, SourceMethodSymbol method, Binder rootBinder, ImmutableMap<SyntaxNode, Binder> map) : base(compilation, root, method) { this.rootBinder = rootBinder; this.map = map; }
/// <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)); }
private void BindPCallAndDelegate(InvocationExpressionSyntax node, ArrayBuilder <BoundExpression> args, DiagnosticBag diagnostics, TypeSyntax type) { var XNode = node.XNode as XP.MethodCallContext; string method = XNode?.Expr.GetText(); if (string.IsNullOrEmpty(method)) { method = "PCALL"; } if (!ValidatePCallArguments(node, args, diagnostics, method)) { return; } var kind = args[0].Kind; if (kind != BoundKind.Local && kind != BoundKind.FieldAccess) { Error(diagnostics, ErrorCode.ERR_PCallFirstArgument, node, method, "typed function pointer"); return; } string methodName = null; // Note that this does not get the syntax of the argument itself // but the syntax of the place where the symbol (Global, Field or Local) that the argument points to was defined SyntaxReference syntaxref = null; if (kind == BoundKind.FieldAccess) { var bfa = args[0] as BoundFieldAccess; // Global or Field if (bfa != null && bfa.ExpressionSymbol.DeclaringSyntaxReferences.Length > 0) { syntaxref = bfa.ExpressionSymbol.DeclaringSyntaxReferences[0] as SyntaxReference; } } else if (kind == BoundKind.Local) { var bl = args[0] as BoundLocal; // Local if (bl != null && bl.LocalSymbol?.DeclaringSyntaxReferences.Length > 0) { syntaxref = bl.LocalSymbol.DeclaringSyntaxReferences[0] as SyntaxReference; } } if (syntaxref != null) { CSharpSyntaxNode syntaxnode = syntaxref.GetSyntax() as CSharpSyntaxNode; var xNode = syntaxnode?.XNode; methodName = GetTypedPtrName(xNode); } if (methodName == null) { // first argument for pcall must be typed ptr Error(diagnostics, ErrorCode.ERR_PCallFirstArgument, node, method, "typed function pointer"); return; } var lookupResult = LookupResult.GetInstance(); HashSet <DiagnosticInfo> useSiteDiagnostics = null; LookupOptions options = LookupOptions.AllMethodsOnArityZero; options |= LookupOptions.MustNotBeInstance; this.LookupSymbolsWithFallback(lookupResult, methodName, arity: 0, useSiteDiagnostics: ref useSiteDiagnostics, options: options); SourceMethodSymbol methodSym = null; if (lookupResult.IsClear) { // Cannot locate types pointer for pcall Error(diagnostics, ErrorCode.ERR_PCallTypedPointerName, node, method, methodName); methodSym = null; } else if (lookupResult.IsMultiViable) { foreach (var symbol in lookupResult.Symbols) { if (symbol.DeclaringCompilation == this.Compilation && symbol is SourceMethodSymbol) { methodSym = (SourceMethodSymbol)symbol; break; } } } else { methodSym = (SourceMethodSymbol)lookupResult.Symbols[0]; } if (methodSym != null) { lookupResult.Clear(); var ts = FindPCallDelegateType(type as IdentifierNameSyntax); if (ts != null && ts.IsDelegateType()) { SourceDelegateMethodSymbol delmeth = ts.DelegateInvokeMethod() as SourceDelegateMethodSymbol; // clone the parameters from the methodSym var builder = ArrayBuilder <ParameterSymbol> .GetInstance(); foreach (var par in methodSym.Parameters) { var parameter = new SourceSimpleParameterSymbol( delmeth, par.Type, par.Ordinal, par.RefKind, par.Name, par.Locations); builder.Add(parameter); } delmeth.InitializeParameters(builder.ToImmutableAndFree()); delmeth.SetReturnType(methodSym.ReturnType); } else { Error(diagnostics, ErrorCode.ERR_PCallResolveGeneratedDelegate, node, method, type.ToString()); } } return; }