private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var methodSymbol = (MethodSymbol)this.MemberSymbol; // Strip off ExecutableCodeBinder (see ctor). Binder binder = this.RootBinder; do { if (binder is ExecutableCodeBinder) { binder = binder.Next; break; } binder = binder.Next; }while (binder != null); Debug.Assert(binder != null); var executablebinder = new ExecutableCodeBinder(body, methodSymbol, binder ?? this.RootBinder); var blockBinder = executablebinder.GetBinder(body).WithAdditionalFlags(GetSemanticModelBinderFlags()); speculativeModel = CreateSpeculative(parentModel, methodSymbol, body, blockBinder, position); return(true); }
public static void IssueDiagnostics( CSharpCompilation compilation, BoundNode node, BindingDiagnosticBag diagnostics, MethodSymbol containingSymbol ) { Debug.Assert(node != null); Debug.Assert((object)containingSymbol != null); ExecutableCodeBinder.ValidateIteratorMethod(compilation, containingSymbol, diagnostics); try { var diagnosticPass = new DiagnosticsPass( compilation, diagnostics, containingSymbol ); diagnosticPass.Visit(node); } catch (CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
internal override bool TryGetSpeculativeSemanticModelCore( SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out SemanticModel speculativeModel ) { var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return(false); } binder = new ExecutableCodeBinder(initializer, binder.ContainingMemberOrLambda, binder); speculativeModel = CreateSpeculative( parentModel, this.MemberSymbol, initializer, binder, GetRemappedSymbols(), position ); return(true); }
private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var methodSymbol = (MethodSymbol)this.MemberSymbol; // Strip off ExecutableCodeBinder (see ctor). Binder binder = this.RootBinder; do { if (binder is ExecutableCodeBinder) { binder = binder.Next; break; } binder = binder.Next; }while (binder != null); Debug.Assert(binder != null); var executablebinder = new ExecutableCodeBinder(body, methodSymbol, binder ?? this.RootBinder); var blockBinder = executablebinder.GetBinder(body).WithAdditionalFlags(GetSemanticModelBinderFlags()); // We don't pass the snapshot manager along here, because we're speculating about an entirely new body and it should not // be influenced by any existing code in the body. speculativeModel = CreateSpeculative(parentModel, methodSymbol, body, blockBinder, snapshotManagerOpt: null, position); return(true); }
private static BoundFieldEqualsValue BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, DiagnosticBag diagnostics) { Debug.Assert(!fieldSymbol.IsMetadataConstant); var fieldsBeingBound = binder.FieldsBeingBound; var sourceField = fieldSymbol as SourceMemberFieldSymbolFromDeclarator; bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound); // If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here: // CONSIDER (tomat): reusing the bound field initializers for implicitly typed fields. DiagnosticBag initializerDiagnostics; if (isImplicitlyTypedField) { initializerDiagnostics = DiagnosticBag.GetInstance(); } else { initializerDiagnostics = diagnostics; } binder = new ExecutableCodeBinder(equalsValueClauseNode, fieldSymbol, new LocalScopeBinder(binder)); BoundFieldEqualsValue boundInitValue = binder.BindFieldInitializer(fieldSymbol, equalsValueClauseNode, initializerDiagnostics); if (isImplicitlyTypedField) { initializerDiagnostics.Free(); } return(boundInitValue); }
/// <summary> /// Creates a SemanticModel for an ArrowExpressionClause, which includes /// an ExecutableCodeBinder and a ScopedExpressionBinder. /// </summary> internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, ArrowExpressionClauseSyntax syntax) { Binder binder = new ExecutableCodeBinder(syntax, owner, rootBinder); binder = new ScopedExpressionBinder(binder, syntax.Expression); return(new MethodBodySemanticModel(compilation, owner, binder, syntax)); }
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return(false); } var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new ExecutableCodeBinder(statement, methodSymbol, binder); // local declaration statements need to be wrapped in a block so the local gets seen if (!statement.IsKind(SyntaxKind.Block)) { binder = new BlockBinder(binder, new SyntaxList <StatementSyntax>(statement)); } speculativeModel = CreateSpeculative(parentModel, methodSymbol, statement, binder, position); return(true); }
private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType, ImmutableArray <TypeSymbol> parameterTypes, ImmutableArray <RefKind> parameterRefKinds) { var diagnostics = DiagnosticBag.GetInstance(); var lambdaSymbol = new LambdaSymbol( binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameterTypes, parameterRefKinds, refKind: CodeAnalysis.RefKind.None, returnType: null, diagnostics: diagnostics); Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: true) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; HashSet <DiagnosticInfo> useSiteDiagnostics = null; // TODO: figure out if this should be somehow merged into BoundLambda.Diagnostics. TypeSymbol returnType = result.InferredReturnType(ref useSiteDiagnostics) ?? LambdaSymbol.InferenceFailureReturnType; lambdaSymbol.SetInferredReturnType(result.RefKind, returnType); return(result); }
private bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CSharpSyntaxNode initializer, out SemanticModel speculativeModel) { Debug.Assert(initializer is EqualsValueClauseSyntax || initializer is ConstructorInitializerSyntax); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return(false); } switch (initializer.Kind()) { case SyntaxKind.EqualsValueClause: binder = new ExecutableCodeBinder(initializer, binder.ContainingMemberOrLambda, binder); break; case SyntaxKind.ThisConstructorInitializer: case SyntaxKind.BaseConstructorInitializer: ArgumentListSyntax argList = ((ConstructorInitializerSyntax)initializer).ArgumentList; if (argList != null) { binder = new ExecutableCodeBinder(argList, binder.ContainingMemberOrLambda, binder); } break; } speculativeModel = CreateSpeculative(parentModel, this.MemberSymbol, initializer, binder, position); return(true); }
private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var methodSymbol = (MethodSymbol)this.MemberSymbol; var executablebinder = new ExecutableCodeBinder(body, methodSymbol, this.rootBinder.Next); // Strip off ExecutableCodeBinder (see ctor). var blockBinder = executablebinder.GetBinder(body).WithAdditionalFlags(BinderFlags.SemanticModel); speculativeModel = CreateSpeculative(parentModel, methodSymbol, body, blockBinder, position); return true; }
private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var methodSymbol = (MethodSymbol)this.MemberSymbol; var executablebinder = new ExecutableCodeBinder(body, methodSymbol, this.rootBinder.Next); // Strip off ExecutableCodeBinder (see ctor). var blockBinder = executablebinder.GetBinder(body).WithAdditionalFlags(BinderFlags.SemanticModel); speculativeModel = CreateSpeculative(parentModel, methodSymbol, body, blockBinder, position); return(true); }
protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, ExecutableCodeBinder lambdaBodyBinder, DiagnosticBag diagnostics) { if (this.IsExpressionLambda) { return(lambdaBodyBinder.BindExpressionLambdaBody((ExpressionSyntax)this.Body, diagnostics)); } else { return(lambdaBodyBinder.BindBlock((BlockSyntax)this.Body, diagnostics)); } }
public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { ExecutableCodeBinder.ValidateIteratorMethod(_compilation, node.Symbol, _diagnostics); var outerLocalFunction = _staticLocalFunction; if (node.Symbol.IsStatic) { _staticLocalFunction = node.Symbol; } var result = base.VisitLocalFunctionStatement(node); _staticLocalFunction = outerLocalFunction; return(result); }
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out SemanticModel speculativeModel) { if ((MemberSymbol as MethodSymbol)?.MethodKind == MethodKind.Constructor) { var binder = this.GetEnclosingBinder(position); if (binder != null) { var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new ExecutableCodeBinder(constructorInitializer, methodSymbol, binder); speculativeModel = CreateSpeculative(parentModel, methodSymbol, constructorInitializer, binder, position); return(true); } } speculativeModel = null; return(false); }
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return(false); } var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new ExecutableCodeBinder(statement, methodSymbol, binder); speculativeModel = CreateSpeculative(parentModel, methodSymbol, statement, binder, position); return(true); }
private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType) { var diagnostics = DiagnosticBag.GetInstance(); var parameters = DelegateParameters(delegateType); var lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, this.unboundLambda, parameters, returnType: null); Binder lambdaBodyBinder = new ExecutableCodeBinder(this.unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); var block = BindLambdaBody(lambdaSymbol, ref lambdaBodyBinder, diagnostics); var result = new BoundLambda(this.unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType) { WasCompilerGenerated = this.unboundLambda.WasCompilerGenerated }; HashSet <DiagnosticInfo> useSiteDiagnostics = null; // TODO: figure out if this should be somehow merged into BoundLambda.Diagnostics. lambdaSymbol.SetInferredReturnType(result.InferredReturnType(ref useSiteDiagnostics) ?? new ExtendedErrorTypeSymbol(binder.Compilation, string.Empty, 0, null)); return(result); }
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return false; } var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new ExecutableCodeBinder(statement, methodSymbol, binder); // local declaration statements need to be wrapped in a block so the local gets seen if (!statement.IsKind(SyntaxKind.Block)) { binder = new BlockBinder(methodSymbol, binder, new SyntaxList<StatementSyntax>(statement)); } speculativeModel = CreateSpeculative(parentModel, methodSymbol, statement, binder, position); return true; }
private static BoundFieldInitializer BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, DiagnosticBag diagnostics) { Debug.Assert(!fieldSymbol.IsMetadataConstant); var fieldsBeingBound = binder.FieldsBeingBound; var sourceField = fieldSymbol as SourceMemberFieldSymbol; bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound); // If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here: // CONSIDER (tomat): reusing the bound field initializers for implicitly typed fields. DiagnosticBag initializerDiagnostics; if (isImplicitlyTypedField) { initializerDiagnostics = DiagnosticBag.GetInstance(); } else { initializerDiagnostics = diagnostics; } binder = new ExecutableCodeBinder(equalsValueClauseNode, fieldSymbol, new LocalScopeBinder(binder)); var boundInitValue = binder.BindVariableOrAutoPropInitializer(equalsValueClauseNode, RefKind.None, fieldSymbol.GetFieldType(fieldsBeingBound), initializerDiagnostics); if (isImplicitlyTypedField) { initializerDiagnostics.Free(); } return(new BoundFieldInitializer( equalsValueClauseNode.Value, //we want the attached sequence point to indicate the value node fieldSymbol, boundInitValue)); }
// 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; }
/// <summary> /// Performs the same function as GetEnclosingBinder, but is known to take place within a /// specified lambda. Walks up the syntax hierarchy until a node with an associated binder /// is found. /// </summary> /// <remarks> /// CONSIDER: can this share code with MemberSemanticModel.GetEnclosingBinder? /// /// Returned binder doesn't need to have <see cref="BinderFlags.SemanticModel"/> set - the caller will add it. /// </remarks> private static Binder GetLambdaEnclosingBinder(int position, CSharpSyntaxNode startingNode, CSharpSyntaxNode containingLambda, ExecutableCodeBinder lambdaBinder) { Debug.Assert(containingLambda.IsAnonymousFunction()); Debug.Assert(LookupPosition.IsInAnonymousFunctionOrQuery(position, containingLambda)); var current = startingNode; while (current != containingLambda) { Debug.Assert(current != null); StatementSyntax stmt = current as StatementSyntax; if (stmt != null) { if (LookupPosition.IsInStatementScope(position, stmt)) { Binder binder = lambdaBinder.GetBinder(current); if (binder != null) { return binder; } } } else if (current.Kind == SyntaxKind.CatchClause) { if (LookupPosition.IsInCatchBlockScope(position, (CatchClauseSyntax)current)) { Binder binder = lambdaBinder.GetBinder(current); if (binder != null) { return binder; } } } else if (current.Kind == SyntaxKind.CatchFilterClause) { if (LookupPosition.IsInCatchFilterScope(position, (CatchFilterClauseSyntax)current)) { Binder binder = lambdaBinder.GetBinder(current); if (binder != null) { return binder; } } } else if (current.IsAnonymousFunction()) { if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current)) { Binder binder = lambdaBinder.GetBinder(current); if (binder != null) { return binder; } } } else { // If this ever breaks, make sure that all callers of // CanHaveAssociatedLocalBinder are in sync. Debug.Assert(!current.CanHaveAssociatedLocalBinder()); } current = current.ParentOrStructuredTriviaParent; } return lambdaBinder; }
private static BoundFieldInitializer BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, DiagnosticBag diagnostics) { Debug.Assert(!fieldSymbol.IsMetadataConstant); var fieldsBeingBound = binder.FieldsBeingBound; var sourceField = fieldSymbol as SourceMemberFieldSymbolFromDeclarator; bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound); // If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here: // CONSIDER (tomat): reusing the bound field initializers for implicitly typed fields. DiagnosticBag initializerDiagnostics; if (isImplicitlyTypedField) { initializerDiagnostics = DiagnosticBag.GetInstance(); } else { initializerDiagnostics = diagnostics; } binder = new ExecutableCodeBinder(equalsValueClauseNode, fieldSymbol, new LocalScopeBinder(binder)); var boundInitValue = binder.BindVariableOrAutoPropInitializer(equalsValueClauseNode, RefKind.None, fieldSymbol.GetFieldType(fieldsBeingBound), initializerDiagnostics); if (isImplicitlyTypedField) { initializerDiagnostics.Free(); } return new BoundFieldInitializer( equalsValueClauseNode.Value, //we want the attached sequence point to indicate the value node fieldSymbol, boundInitValue); }
private static Binder GetEnclosingBinder(SyntaxNode node, int position, Binder rootBinder, SyntaxNode root) { if (node == root) { return rootBinder.GetBinder(node) ?? rootBinder; } Debug.Assert(root.Contains(node)); ExpressionSyntax typeOfArgument = null; SyntaxNode unexpectedAnonymousFunction = null; // Keep track of which fix-up should be applied first. If we see a typeof expression inside an unexpected // anonymous function, that the typeof binder should be innermost (i.e. should have the unexpected // anonymous function binder as its Next). // NOTE: only meaningful if typeOfArgument is non-null; bool typeOfEncounteredBeforeUnexpectedAnonymousFunction = false; Binder binder = null; for (var current = node; binder == null; current = current.ParentOrStructuredTriviaParent) { Debug.Assert(current != null); // Why were we asked for an enclosing binder for a node outside our root? StatementSyntax stmt = current as StatementSyntax; TypeOfExpressionSyntax typeOfExpression; if (stmt != null) { if (LookupPosition.IsInStatementScope(position, stmt)) { binder = rootBinder.GetBinder(current); if (binder != null) { binder = AdjustBinderForPositionWithinStatement(position, binder, stmt); } } } else if (current.Kind() == SyntaxKind.CatchClause) { if (LookupPosition.IsInCatchBlockScope(position, (CatchClauseSyntax)current)) { binder = rootBinder.GetBinder(current); } } else if (current.Kind() == SyntaxKind.CatchFilterClause) { if (LookupPosition.IsInCatchFilterScope(position, (CatchFilterClauseSyntax)current)) { binder = rootBinder.GetBinder(current); } } else if (current.IsAnonymousFunction()) { if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current)) { binder = rootBinder.GetBinder(current); // This should only happen in error scenarios. For example, C# does not allow array rank // specifiers in types, (e.g. int[1] x;), but the syntax model does. In order to construct // an appropriate binder chain for the anonymous method body, we need to construct an // ExecutableCodeBinder. if (binder == null && unexpectedAnonymousFunction == null && current != root) { unexpectedAnonymousFunction = current; } } } else if (current.Kind() == SyntaxKind.TypeOfExpression && typeOfArgument == null && LookupPosition.IsBetweenTokens( position, (typeOfExpression = (TypeOfExpressionSyntax)current).OpenParenToken, typeOfExpression.CloseParenToken)) { typeOfArgument = typeOfExpression.Type; typeOfEncounteredBeforeUnexpectedAnonymousFunction = unexpectedAnonymousFunction == null; } else if (current.Kind() == SyntaxKind.SwitchSection) { if (LookupPosition.IsInSwitchSectionScope(position, (SwitchSectionSyntax)current)) { binder = rootBinder.GetBinder(current); } } else if (current.Kind() == SyntaxKind.ArgumentList) { var argList = (ArgumentListSyntax)current; if (LookupPosition.IsBetweenTokens(position, argList.OpenParenToken, argList.CloseParenToken)) { binder = rootBinder.GetBinder(current); } } else if (current.Kind() == SyntaxKind.EqualsValueClause) { binder = rootBinder.GetBinder(current); } else if (current.Kind() == SyntaxKind.Attribute) { binder = rootBinder.GetBinder(current); } else if (current.Kind() == SyntaxKind.ArrowExpressionClause) { binder = rootBinder.GetBinder(current); } else if (current is ExpressionSyntax && ((current.Parent as LambdaExpressionSyntax)?.Body == current || (current.Parent as SwitchStatementSyntax)?.Expression == current || (current.Parent as CommonForEachStatementSyntax)?.Expression == current)) { binder = rootBinder.GetBinder(current); } else if (current is VariableComponentSyntax && (current.Parent as ForEachComponentStatementSyntax)?.VariableComponent == current) { binder = rootBinder.GetBinder(current.Parent); } else if (current is VariableComponentSyntax && (current.Parent is VariableComponentAssignmentSyntax) && (current.Parent.Parent as ForStatementSyntax)?.Deconstruction == current) { binder = rootBinder.GetBinder(current.Parent.Parent); } else if (current is VariableComponentSyntax && (current.Parent is VariableComponentAssignmentSyntax) && (current.Parent.Parent as DeconstructionDeclarationStatementSyntax)?.Assignment.VariableComponent == current) { binder = rootBinder.GetBinder(current.Parent.Parent); } else { // If this ever breaks, make sure that all callers of // CanHaveAssociatedLocalBinder are in sync. Debug.Assert(!current.CanHaveAssociatedLocalBinder()); } if (current == root) { break; } } binder = binder ?? rootBinder.GetBinder(root) ?? rootBinder; Debug.Assert(binder != null); if (typeOfArgument != null && !typeOfEncounteredBeforeUnexpectedAnonymousFunction) { binder = new TypeofBinder(typeOfArgument, binder); } if (unexpectedAnonymousFunction != null) { binder = new ExecutableCodeBinder(unexpectedAnonymousFunction, new LambdaSymbol(binder.ContainingMemberOrLambda, ImmutableArray<ParameterSymbol>.Empty, RefKind.None, ErrorTypeSymbol.UnknownResultType, unexpectedAnonymousFunction.Kind() == SyntaxKind.AnonymousMethodExpression ? MessageID.IDS_AnonMethod : MessageID.IDS_Lambda, unexpectedAnonymousFunction, isSynthesized: false), binder); } if (typeOfArgument != null && typeOfEncounteredBeforeUnexpectedAnonymousFunction) { binder = new TypeofBinder(typeOfArgument, binder); } return binder; }
/// <summary> /// Bind the constructor initializer in the context of the specified location and get semantic information /// such as type, symbols and diagnostics. This method is used to get semantic information about a constructor /// initializer that did not actually appear in the source code. /// /// NOTE: This will only work in locations where there is already a constructor initializer. /// </summary> /// <param name="position">A character position used to identify a declaration scope and accessibility. This /// character position must be within the FullSpan of the Root syntax node in this SemanticModel. /// Furthermore, it must be within the span of an existing constructor initializer. /// </param> /// <param name="constructorInitializer">A syntax node that represents a parsed constructor initializer. This syntax node /// need not and typically does not appear in the source code referred to SemanticModel instance.</param> /// <returns>The semantic information for the topmost node of the constructor initializer.</returns> public SymbolInfo GetSpeculativeSymbolInfo(int position, ConstructorInitializerSyntax constructorInitializer) { Debug.Assert(CanGetSemanticInfo(constructorInitializer, isSpeculative: true)); position = CheckAndAdjustPosition(position); if (constructorInitializer == null) { throw new ArgumentNullException(nameof(constructorInitializer)); } // NOTE: since we're going to be depending on a MemberModel to do the binding for us, // we need to find a constructor initializer in the tree of this semantic model. // NOTE: This approach will not allow speculative binding of a constructor initializer // on a constructor that didn't formerly have one. // TODO: Should we support positions that are not in existing constructor initializers? // If so, we will need to build up the context that would otherwise be built up by // InitializerMemberModel. var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType<ConstructorInitializerSyntax>().FirstOrDefault(); if (existingConstructorInitializer == null) { return SymbolInfo.None; } MemberSemanticModel memberModel = GetMemberModel(existingConstructorInitializer); if (memberModel == null) { return SymbolInfo.None; } var binder = this.GetEnclosingBinder(position); if (binder != null) { var diagnostics = DiagnosticBag.GetInstance(); if (constructorInitializer.ArgumentList != null) { binder = new ExecutableCodeBinder(constructorInitializer.ArgumentList, binder.ContainingMemberOrLambda, binder); } var bnode = memberModel.Bind(binder, constructorInitializer, diagnostics); var binfo = memberModel.GetSymbolInfoForNode(SymbolInfoOptions.DefaultOptions, bnode, bnode, boundNodeForSyntacticParent: null, binderOpt: binder); diagnostics.Free(); return binfo; } else { return SymbolInfo.None; } }
/// <summary> /// Creates a SemanticModel for the method. /// </summary> internal static MethodBodySemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, MethodSymbol owner, ExecutableCodeBinder executableCodeBinder, CSharpSyntaxNode syntax, BoundNode boundNode = null) { Debug.Assert(containingSemanticModel != null); var result = new MethodBodySemanticModel(owner, executableCodeBinder, syntax, containingSemanticModel); if (boundNode != null) { result.UnguardedAddBoundTreeForStandaloneSyntax(syntax, boundNode); } return(result); }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { Debug.Assert((object)scriptCtor != null); firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray <FieldOrPropertyInitializer> siblingInitializers = initializers[i]; // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)initializerNode, diagnostics); } else if (initializerNode.Kind() == SyntaxKind.LabeledStatement) { // TODO: labels in interactive var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray <BoundNode> .Empty, true); boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement); } else { var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(collisionDetector, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
/// <summary> /// Creates an AttributeSemanticModel that allows asking semantic questions about an attribute node. /// </summary> public static AttributeSemanticModel Create(CSharpCompilation compilation, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder) { var executableBinder = new ExecutableCodeBinder(syntax, attributeType, rootBinder); return new AttributeSemanticModel(compilation, syntax, attributeType, aliasOpt, new LocalScopeBinder(executableBinder)); }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var invokeMethod = DelegateInvokeMethod(delegateType); RefKind refKind; var returnType = DelegateReturnType(invokeMethod, out refKind); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. var cacheKey = ReturnInferenceCacheKey.Create(delegateType, IsAsync); BoundLambda returnInferenceLambda; if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType) { lambdaSymbol = returnInferenceLambda.Symbol; if ((object)LambdaSymbol.InferenceFailureReturnType != lambdaSymbol.ReturnType && lambdaSymbol.ReturnType == returnType && lambdaSymbol.RefKind == refKind) { lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } } lambdaSymbol = new LambdaSymbol( binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, cacheKey.ParameterTypes, cacheKey.ParameterRefKinds, refKind, returnType); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); ((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics); ValidateUnsafeParameters(diagnostics, cacheKey.ParameterTypes); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(invokeMethod)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.DiagnosticLocation, this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && !returnType.IsNonGenericTaskType(binder.Compilation) && !returnType.IsGenericTaskType(binder.Compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.DiagnosticLocation, lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.DiagnosticLocation); } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return(result); }
public BoundLambda(CSharpSyntaxNode syntax, BoundBlock body, ImmutableArray <Diagnostic> diagnostics, ExecutableCodeBinder binder, TypeSymbol type) : this(syntax, (LambdaSymbol)binder.MemberSymbol, body, diagnostics, binder, type) { }
// 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); }
protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, ExecutableCodeBinder lambdaBodyBinder, DiagnosticBag diagnostics) { return(bodyResolver(lambdaSymbol, lambdaBodyBinder, diagnostics)); }
public BoundLambda(CSharpSyntaxNode syntax, BoundBlock body, ImmutableArray<Diagnostic> diagnostics, ExecutableCodeBinder binder, TypeSymbol type) : this(syntax, (LambdaSymbol)binder.MemberSymbol, body, diagnostics, binder, type) { }
/// <summary> /// Creates a SemanticModel for an ArrowExpressionClause, which includes /// an ExecutableCodeBinder and a ScopedExpressionBinder. /// </summary> internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, ArrowExpressionClauseSyntax syntax) { Binder binder = new ExecutableCodeBinder(syntax, owner, rootBinder); return new MethodBodySemanticModel(compilation, owner, binder, syntax); }
protected abstract BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, ExecutableCodeBinder binder, DiagnosticBag diagnostics);
protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, ExecutableCodeBinder lambdaBodyBinder, DiagnosticBag diagnostics) { return bodyResolver(lambdaSymbol, lambdaBodyBinder, diagnostics); }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var invokeMethod = DelegateInvokeMethod(delegateType); RefKind refKind; var returnType = DelegateReturnType(invokeMethod, out refKind); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. MethodSymbol cacheKey = GetCacheKey(delegateType); BoundLambda returnInferenceLambda; if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType && returnInferenceLambda.Symbol.ReturnType == returnType) { lambdaSymbol = returnInferenceLambda.Symbol; Debug.Assert(lambdaSymbol.RefKind == refKind); lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } var parameters = DelegateParameters(invokeMethod); lambdaSymbol = new LambdaSymbol( binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, refKind, returnType); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); ((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics); ValidateUnsafeParameters(diagnostics, parameters); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(invokeMethod)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.Locations[0], this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && !returnType.IsNonGenericTaskType(binder.Compilation) && !returnType.IsGenericTaskType(binder.Compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.Locations[0], lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.Locations[0]); } // This is an attempt to get a repro for https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481 if ((object)returnType != null && returnType.SpecialType != SpecialType.System_Void && !block.HasErrors && !diagnostics.HasAnyResolvedErrors() && block.Statements.Length > 0) { BoundStatement first = block.Statements[0]; if (first.Kind == BoundKind.ReturnStatement) { var returnStmt = (BoundReturnStatement)first; if (returnStmt.ExpressionOpt != null && (object)returnStmt.ExpressionOpt.Type == null) { throw ExceptionUtilities.Unreachable; } } } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return result; }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var returnType = DelegateReturnType(delegateType); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. MethodSymbol cacheKey = GetCacheKey(delegateType); BoundLambda returnInferenceLambda; if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType) { var lambdaSym = returnInferenceLambda.Symbol; var lambdaRetType = lambdaSym.ReturnType; if (lambdaRetType == returnType) { lambdaSymbol = lambdaSym; lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } } var parameters = DelegateParameters(delegateType); lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, returnType); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, ref lambdaBodyBinder, diagnostics); ValidateUnsafeParameters(diagnostics, parameters); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(delegateType)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.Locations[0], this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol, _unboundLambda.Syntax); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && returnType != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) && returnType.OriginalDefinition != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.Locations[0], lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol, diagnostics, lambdaSymbol.Locations[0]); } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return result; }
/// <summary> /// Bind the given attribute speculatively at the given position, and return back /// the resulting bound node. May return null in some error cases. /// </summary> private BoundAttribute GetSpeculativelyBoundAttribute(int position, AttributeSyntax attribute, out Binder binder) { if (attribute == null) { throw new ArgumentNullException(nameof(attribute)); } binder = this.GetSpeculativeBinderForAttribute(position); if (binder == null) { return null; } var diagnostics = DiagnosticBag.GetInstance(); AliasSymbol aliasOpt; // not needed. NamedTypeSymbol attributeType = (NamedTypeSymbol)binder.BindType(attribute.Name, diagnostics, out aliasOpt); var boundNode = new ExecutableCodeBinder(attribute, binder.ContainingMemberOrLambda, binder).BindAttribute(attribute, attributeType, diagnostics); diagnostics.Free(); return boundNode; }
/// <summary> /// Creates a SemanticModel for the method. /// </summary> internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, ExecutableCodeBinder executableCodeBinder, CSharpSyntaxNode syntax, BoundNode boundNode = null) { var result = new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax); if (boundNode != null) { result.UnguardedAddBoundTreeForStandaloneSyntax(syntax, boundNode); } return(result); }
/// <summary> /// This overload exists for callers who /// a) Already have a node in hand and don't want to search through the tree /// b) May want to search from an indirect container (e.g. node containing node /// containing position). /// </summary> private Binder GetEnclosingBinder(CSharpSyntaxNode node, int position) { AssertPositionAdjusted(position); if (node == this.root) { return RootBinder; } ExpressionSyntax typeOfArgument = null; CSharpSyntaxNode unexpectedAnonymousFunction = null; // Keep track of which fix-up should be applied first. If we see a typeof expression inside an unexpected // anonymous function, that the typeof binder should be innermost (i.e. should have the unexpected // anonymous function binder as its Next). // NOTE: only meaningful if typeOfArgument is non-null; bool typeOfEncounteredBeforeUnexpectedAnonymousFunction = false; Binder binder = null; for (var current = node; binder == null; current = current.ParentOrStructuredTriviaParent) { Debug.Assert(current != null); // Why were we asked for an enclosing binder for a node outside our root? StatementSyntax stmt = current as StatementSyntax; if (stmt != null) { if (LookupPosition.IsInStatementScope(position, stmt)) { binder = RootBinder.GetBinder(current); if (binder != null) { binder = AdjustBinderForPositionWithinStatement(position, binder, stmt); } } } else if (current.Kind == SyntaxKind.CatchClause) { if (LookupPosition.IsInCatchBlockScope(position, (CatchClauseSyntax)current)) { binder = RootBinder.GetBinder(current); } } else if (current.Kind == SyntaxKind.CatchFilterClause) { if (LookupPosition.IsInCatchFilterScope(position, (CatchFilterClauseSyntax)current)) { binder = RootBinder.GetBinder(current); } } else if (current.IsAnonymousFunction()) { if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current)) { binder = RootBinder.GetBinder(current); // This should only happen in error scenarios. For example, C# does not allow array rank // specifiers in types, (e.g. int[1] x;), but the syntax model does. In order to construct // an appropriate binder chain for the anonymous method body, we need to construct an // ExecutableCodeBinder. if (binder == null && unexpectedAnonymousFunction == null) { unexpectedAnonymousFunction = current; } } } else if (current.Kind == SyntaxKind.TypeOfExpression && typeOfArgument == null) { typeOfArgument = ((TypeOfExpressionSyntax)current).Type; typeOfEncounteredBeforeUnexpectedAnonymousFunction = unexpectedAnonymousFunction == null; } else { // If this ever breaks, make sure that all callers of // CanHaveAssociatedLocalBinder are in sync. Debug.Assert(!current.CanHaveAssociatedLocalBinder()); } if (current == this.root) { break; } } binder = binder ?? RootBinder; Debug.Assert(binder != null); if (typeOfArgument != null && !typeOfEncounteredBeforeUnexpectedAnonymousFunction) { binder = new TypeofBinder(typeOfArgument, binder); } if (unexpectedAnonymousFunction != null) { binder = new ExecutableCodeBinder(unexpectedAnonymousFunction, ErrorMethodSymbol.UnknownMethod, binder); } if (typeOfArgument != null && typeOfEncounteredBeforeUnexpectedAnonymousFunction) { binder = new TypeofBinder(typeOfArgument, binder); } return binder.WithAdditionalFlags(BinderFlags.SemanticModel); }
private bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CSharpSyntaxNode initializer, out SemanticModel speculativeModel) { Debug.Assert(initializer is EqualsValueClauseSyntax || initializer is ConstructorInitializerSyntax); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return false; } switch (initializer.Kind()) { case SyntaxKind.EqualsValueClause: binder = new ExecutableCodeBinder(initializer, binder.ContainingMemberOrLambda, binder); break; case SyntaxKind.ThisConstructorInitializer: case SyntaxKind.BaseConstructorInitializer: ArgumentListSyntax argList = ((ConstructorInitializerSyntax)initializer).ArgumentList; if (argList != null) { binder = new ExecutableCodeBinder(argList, binder.ContainingMemberOrLambda, binder); } break; } speculativeModel = CreateSpeculative(parentModel, this.MemberSymbol, initializer, binder, position); return true; }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializer, ImmutableArray<ImmutableArray<FieldOrPropertyInitializer>> initializers, ArrayBuilder<BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray<FieldOrPropertyInitializer> siblingInitializers = initializers[i]; // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; // Label instances must be shared across all global statements. ScriptLocalScopeBinder.Labels labels = null; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; var syntaxTree = syntaxRef.SyntaxTree; Debug.Assert(syntaxTree.Options.Kind != SourceCodeKind.Regular); var syntax = (CSharpSyntaxNode)syntaxRef.GetSyntax(); var syntaxRoot = syntaxTree.GetCompilationUnitRoot(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxTree); labels = new ScriptLocalScopeBinder.Labels(scriptInitializer, syntaxRoot); } Binder scriptClassBinder = binderFactory.GetBinder(syntax); Debug.Assert(((NamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } Binder parentBinder = new ExecutableCodeBinder( syntaxRoot, scriptInitializer, new ScriptLocalScopeBinder(labels, scriptClassBinder)); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( parentBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)syntax, diagnostics); } else { boundInitializer = BindGlobalStatement( parentBinder, scriptInitializer, (StatementSyntax)syntax, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
private Binder GetFieldOrPropertyInitializerBinder(FieldSymbol symbol, Binder outer, EqualsValueClauseSyntax initializer) { BinderFlags flags = BinderFlags.None; // NOTE: checking for a containing script class is sufficient, but the regular C# test is quick and easy. if (this.IsRegularCSharp || !symbol.ContainingType.IsScriptClass) { flags |= BinderFlags.FieldInitializer; } outer = new LocalScopeBinder(outer).WithAdditionalFlagsAndContainingMemberOrLambda(flags, symbol); if (initializer != null) { outer = new ExecutableCodeBinder(initializer, symbol, outer); } return outer; }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var returnType = DelegateReturnType(delegateType); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. MethodSymbol cacheKey = GetCacheKey(delegateType); BoundLambda returnInferenceLambda; if (returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType) { var lambdaSym = returnInferenceLambda.Symbol; var lambdaRetType = lambdaSym.ReturnType; if (lambdaRetType == returnType) { lambdaSymbol = lambdaSym; lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } } var parameters = DelegateParameters(delegateType); lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, this.unboundLambda, parameters, returnType); lambdaBodyBinder = new ExecutableCodeBinder(this.unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, ref lambdaBodyBinder, diagnostics); ValidateUnsafeParameters(diagnostics, parameters); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(delegateType)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.Locations[0], this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol, this.unboundLambda.Syntax); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && returnType != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task) && returnType.OriginalDefinition != binder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.Locations[0], lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol, diagnostics, lambdaSymbol.Locations[0]); } var result = new BoundLambda(this.unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType) { WasCompilerGenerated = this.unboundLambda.WasCompilerGenerated }; return(result); }
// Create a member model for the given declaration syntax. In certain very malformed // syntax trees, there may not be a symbol that can have a member model associated with it // (although we try to minimize such cases). In such cases, null is returned. private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node) { var outer = _binderFactory.GetBinder(node); if (this.IgnoresAccessibility) { outer = outer.WithAdditionalFlags(BinderFlags.IgnoreAccessibility); } switch (node.Kind()) { case SyntaxKind.Block: MemberDeclarationSyntax memberDecl; AccessorDeclarationSyntax accessorDecl; if ((memberDecl = node.Parent as MemberDeclarationSyntax) != null) { var symbol = (SourceMethodSymbol)GetDeclaredSymbol(memberDecl); if ((object)symbol == null) return null; return MethodBodySemanticModel.Create(this.Compilation, symbol, outer, memberDecl); } else if ((accessorDecl = node.Parent as AccessorDeclarationSyntax) != null) { var symbol = (SourceMethodSymbol)GetDeclaredSymbol(accessorDecl); if ((object)symbol == null) return null; return MethodBodySemanticModel.Create(this.Compilation, symbol, outer, accessorDecl); } else { Debug.Assert(false, "Unexpected node: " + node.Parent); return null; } case SyntaxKind.EqualsValueClause: switch (node.Parent.Kind()) { case SyntaxKind.VariableDeclarator: { var variableDecl = (VariableDeclaratorSyntax)node.Parent; SourceMemberFieldSymbol fieldSymbol = GetDeclaredFieldSymbol(variableDecl); return InitializerSemanticModel.Create( this.Compilation, variableDecl, //pass in the entire field initializer to permit region analysis. fieldSymbol, //if we're in regular C#, then insert an extra binder to perform field initialization checks GetFieldOrPropertyInitializerBinder(fieldSymbol, outer, variableDecl.Initializer)); } case SyntaxKind.PropertyDeclaration: { var propertyDecl = (PropertyDeclarationSyntax)node.Parent; var propertySymbol = (SourcePropertySymbol)GetDeclaredSymbol(propertyDecl); return InitializerSemanticModel.Create( this.Compilation, propertyDecl, propertySymbol, GetFieldOrPropertyInitializerBinder(propertySymbol.BackingField, outer, propertyDecl.Initializer)); } case SyntaxKind.Parameter: { // NOTE: we don't need to create a member model for lambda parameter default value // (which is bad code anyway) because lambdas only appear in code with associated // member models. ParameterSyntax parameterDecl = (ParameterSyntax)node.Parent; ParameterSymbol parameterSymbol = GetDeclaredNonLambdaParameterSymbol(parameterDecl); if ((object)parameterSymbol == null) return null; return InitializerSemanticModel.Create( this.Compilation, parameterDecl, parameterSymbol, outer.CreateBinderForParameterDefaultValue(parameterSymbol, (EqualsValueClauseSyntax)node)); } case SyntaxKind.EnumMemberDeclaration: { var enumDecl = (EnumMemberDeclarationSyntax)node.Parent; var enumSymbol = (FieldSymbol)GetDeclaredSymbol(enumDecl); if ((object)enumSymbol == null) return null; return InitializerSemanticModel.Create( this.Compilation, enumDecl, enumSymbol, GetFieldOrPropertyInitializerBinder(enumSymbol, outer, enumDecl.EqualsValue)); } default: throw ExceptionUtilities.UnexpectedValue(node.Parent.Kind()); } case SyntaxKind.ArrowExpressionClause: { SourceMethodSymbol symbol = null; MemberDeclarationSyntax memberSyntax; var exprDecl = (ArrowExpressionClauseSyntax)node; if (node.Parent is BasePropertyDeclarationSyntax) { symbol = (SourceMethodSymbol)GetDeclaredSymbol(exprDecl); } else if ((memberSyntax = node.Parent as MemberDeclarationSyntax) != null) { symbol = (SourceMethodSymbol)GetDeclaredSymbol(node.Parent as MemberDeclarationSyntax); } else { // Don't throw, just use for the assert ExceptionUtilities.UnexpectedValue(node.Parent); } if ((object)symbol == null) return null; return MethodBodySemanticModel.Create( _compilation, symbol, outer.WithContainingMemberOrLambda(symbol), exprDecl); } case SyntaxKind.GlobalStatement: { Debug.Assert(!this.IsRegularCSharp); var parent = node.Parent; // TODO (tomat): handle misplaced global statements if (parent.Kind() == SyntaxKind.CompilationUnit) { var scriptInitializer = _compilation.ScriptClass.GetScriptInitializer(); Debug.Assert((object)scriptInitializer != null); if ((object)scriptInitializer == null) { return null; } // Share labels across all global statements. if (_globalStatementLabels == null) { Interlocked.CompareExchange(ref _globalStatementLabels, new ScriptLocalScopeBinder.Labels(scriptInitializer, (CompilationUnitSyntax)parent), null); } return MethodBodySemanticModel.Create( this.Compilation, scriptInitializer, new ScriptLocalScopeBinder(_globalStatementLabels, outer), node); } } break; case SyntaxKind.BaseConstructorInitializer: case SyntaxKind.ThisConstructorInitializer: { var constructorDecl = (ConstructorDeclarationSyntax)node.Parent; var constructorSymbol = (SourceMethodSymbol)GetDeclaredSymbol(constructorDecl); if ((object)constructorSymbol == null) return null; // insert an extra binder to perform constructor initialization checks // Handle scoping for possible pattern variables declared in the initializer Binder initializerBinder = outer.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructorSymbol); ArgumentListSyntax argumentList = ((ConstructorInitializerSyntax)node).ArgumentList; if (argumentList != null) { initializerBinder = new ExecutableCodeBinder(argumentList, constructorSymbol, initializerBinder); } return InitializerSemanticModel.Create( this.Compilation, (ConstructorInitializerSyntax)node, constructorSymbol, initializerBinder); } case SyntaxKind.Attribute: { var attribute = (AttributeSyntax)node; AliasSymbol aliasOpt; DiagnosticBag discarded = DiagnosticBag.GetInstance(); var attributeType = (NamedTypeSymbol)outer.BindType(attribute.Name, discarded, out aliasOpt); discarded.Free(); return AttributeSemanticModel.Create( _compilation, attribute, attributeType, aliasOpt, outer.WithAdditionalFlags(BinderFlags.AttributeArgument)); } } return null; }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray<ImmutableArray<FieldInitializer>> initializers, ArrayBuilder<BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList<Imports> firstDebugImports) { Debug.Assert((object)scriptCtor != null); firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray<FieldInitializer> siblingInitializers = initializers[i]; // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.Field; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportsList; } Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)initializerNode, diagnostics); } else if (initializerNode.Kind == SyntaxKind.LabeledStatement) { // TODO: labels in interactive var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray<BoundNode>.Empty, true); boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement); } else { var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(collisionDetector, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var binder = this.GetEnclosingBinder(position); if (binder == null) { speculativeModel = null; return false; } var methodSymbol = (MethodSymbol)this.MemberSymbol; binder = new ExecutableCodeBinder(expressionBody, methodSymbol, binder); speculativeModel = CreateSpeculative(parentModel, methodSymbol, expressionBody, binder, position); return true; }
/// <summary> /// Creates a SemanticModel that creates and owns the ExecutableCodeBinder for the method of which it is a model. /// </summary> internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, CSharpSyntaxNode syntax) { var executableCodeBinder = new ExecutableCodeBinder(syntax, owner, rootBinder); return(new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax)); }
private bool GetSpeculativeSemanticModelForMethodBody(SyntaxTreeSemanticModel parentModel, int position, BlockSyntax body, out SemanticModel speculativeModel) { position = CheckAndAdjustPosition(position); var methodSymbol = (MethodSymbol)this.MemberSymbol; // Strip off ExecutableCodeBinder (see ctor). Binder binder = this.RootBinder; do { if (binder is ExecutableCodeBinder) { binder = binder.Next; break; } binder = binder.Next; } while (binder != null); Debug.Assert(binder != null); var executablebinder = new ExecutableCodeBinder(body, methodSymbol, binder ?? this.RootBinder); var blockBinder = executablebinder.GetBinder(body).WithAdditionalFlags(GetSemanticModelBinderFlags()); speculativeModel = CreateSpeculative(parentModel, methodSymbol, body, blockBinder, position); return true; }
protected override BoundBlock BindLambdaBody(LambdaSymbol lambdaSymbol, ExecutableCodeBinder lambdaBodyBinder, DiagnosticBag diagnostics) { return this.IsExpressionLambda ? lambdaBodyBinder.BindExpressionLambdaBody((ExpressionSyntax)this.Body, diagnostics) : lambdaBodyBinder.BindBlock((BlockSyntax)this.Body, diagnostics); }
/// <summary> /// Creates an AttributeSemanticModel that allows asking semantic questions about an attribute node. /// </summary> public static AttributeSemanticModel Create(CSharpCompilation compilation, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder) { var executableBinder = new ExecutableCodeBinder(syntax, attributeType, rootBinder); return(new AttributeSemanticModel(compilation, syntax, attributeType, aliasOpt, new LocalScopeBinder(executableBinder))); }
internal CSharpAttributeData GetAttribute(AttributeSyntax node, NamedTypeSymbol boundAttributeType, DiagnosticBag diagnostics) { var boundAttribute = new ExecutableCodeBinder(node, this.ContainingMemberOrLambda, this).BindAttribute(node, boundAttributeType, diagnostics); return GetAttribute(boundAttribute, diagnostics); }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers( CSharpCompilation compilation, SynthesizedInteractiveInitializerMethod scriptInitializer, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray <FieldOrPropertyInitializer> siblingInitializers = initializers[i]; // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; // Label instances must be shared across all global statements. ScriptLocalScopeBinder.Labels labels = null; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; var syntaxTree = syntaxRef.SyntaxTree; Debug.Assert(syntaxTree.Options.Kind != SourceCodeKind.Regular); var syntax = (CSharpSyntaxNode)syntaxRef.GetSyntax(); var syntaxRoot = syntaxTree.GetCompilationUnitRoot(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxTree); labels = new ScriptLocalScopeBinder.Labels(scriptInitializer, syntaxRoot); } Binder scriptClassBinder = binderFactory.GetBinder(syntax); Debug.Assert(((NamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } Binder parentBinder = new ExecutableCodeBinder( syntaxRoot, scriptInitializer, new ScriptLocalScopeBinder(labels, scriptClassBinder)); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( parentBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)syntax, diagnostics); } else { boundInitializer = BindGlobalStatement( parentBinder, scriptInitializer, (StatementSyntax)syntax, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
/// <summary> /// Creates a SemanticModel that creates and owns the ExecutableCodeBinder for the method of which it is a model. /// </summary> internal static MethodBodySemanticModel Create(CSharpCompilation compilation, MethodSymbol owner, Binder rootBinder, CSharpSyntaxNode syntax) { var executableCodeBinder = new ExecutableCodeBinder(syntax, owner, rootBinder); return new MethodBodySemanticModel(compilation, owner, executableCodeBinder, syntax); }
private BoundLambda ReallyBind(NamedTypeSymbol delegateType) { var invokeMethod = DelegateInvokeMethod(delegateType); RefKind refKind; var returnType = DelegateReturnType(invokeMethod, out refKind); LambdaSymbol lambdaSymbol; Binder lambdaBodyBinder; BoundBlock block; var diagnostics = DiagnosticBag.GetInstance(); // when binding for real (not for return inference), there is still // a good chance that we could reuse a body of a lambda previously bound for // return type inference. MethodSymbol cacheKey = GetCacheKey(delegateType); BoundLambda returnInferenceLambda; if (_returnInferenceCache.TryGetValue(cacheKey, out returnInferenceLambda) && returnInferenceLambda.InferredFromSingleType && returnInferenceLambda.Symbol.ReturnType == returnType) { lambdaSymbol = returnInferenceLambda.Symbol; Debug.Assert(lambdaSymbol.RefKind == refKind); lambdaBodyBinder = returnInferenceLambda.Binder; block = returnInferenceLambda.Body; diagnostics.AddRange(returnInferenceLambda.Diagnostics); goto haveLambdaBodyAndBinders; } var parameters = DelegateParameters(invokeMethod); lambdaSymbol = new LambdaSymbol( binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, refKind, returnType); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics); ((ExecutableCodeBinder)lambdaBodyBinder).ValidateIteratorMethods(diagnostics); ValidateUnsafeParameters(diagnostics, parameters); haveLambdaBodyAndBinders: bool reachableEndpoint = ControlFlowPass.Analyze(binder.Compilation, lambdaSymbol, block, diagnostics); if (reachableEndpoint) { if (DelegateNeedsReturn(invokeMethod)) { // Not all code paths return a value in {0} of type '{1}' diagnostics.Add(ErrorCode.ERR_AnonymousReturnExpected, lambdaSymbol.Locations[0], this.MessageID.Localize(), delegateType); } else { block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol); } } if (IsAsync && !ErrorFacts.PreventsSuccessfulDelegateConversion(diagnostics)) { if ((object)returnType != null && // Can be null if "delegateType" is not actually a delegate type. returnType.SpecialType != SpecialType.System_Void && !returnType.IsNonGenericTaskType(binder.Compilation) && !returnType.IsGenericTaskType(binder.Compilation)) { // Cannot convert async {0} to delegate type '{1}'. An async {0} may return void, Task or Task<T>, none of which are convertible to '{1}'. diagnostics.Add(ErrorCode.ERR_CantConvAsyncAnonFuncReturns, lambdaSymbol.Locations[0], lambdaSymbol.MessageID.Localize(), delegateType); } } if (IsAsync) { Debug.Assert(lambdaSymbol.IsAsync); SourceMemberMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.Locations[0]); } // This is an attempt to get a repro for https://devdiv.visualstudio.com/DevDiv/_workitems?id=278481 if ((object)returnType != null && returnType.SpecialType != SpecialType.System_Void && !block.HasErrors && !diagnostics.HasAnyResolvedErrors() && block.Statements.Length > 0) { BoundStatement first = block.Statements[0]; if (first.Kind == BoundKind.ReturnStatement) { var returnStmt = (BoundReturnStatement)first; if (returnStmt.ExpressionOpt != null && (object)returnStmt.ExpressionOpt.Type == null) { throw ExceptionUtilities.Unreachable; } } } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return(result); }
private BoundLambda ReallyInferReturnType(NamedTypeSymbol delegateType) { var diagnostics = DiagnosticBag.GetInstance(); var parameters = DelegateParameters(delegateType); var lambdaSymbol = new LambdaSymbol(binder.Compilation, binder.ContainingMemberOrLambda, _unboundLambda, parameters, returnType: null); Binder lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); var block = BindLambdaBody(lambdaSymbol, ref lambdaBodyBinder, diagnostics); var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: true) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; HashSet<DiagnosticInfo> useSiteDiagnostics = null; // TODO: figure out if this should be somehow merged into BoundLambda.Diagnostics. lambdaSymbol.SetInferredReturnType(result.InferredReturnType(ref useSiteDiagnostics) ?? new ExtendedErrorTypeSymbol(binder.Compilation, string.Empty, 0, null)); return result; }