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); }
// Tests just the errors found while binding method M in class C. public void TestErrors(string code, params string[] errors) { var compilation = CreateCompilationWithMscorlib(code); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var factory = compilation.GetBinderFactory(method.SyntaxTree); var parameterBinderContext = factory.GetBinder(method.BlockSyntax); var binder = new ExecutableCodeBinder(method.BlockSyntax.Parent, method, parameterBinderContext); var diagnostics = new DiagnosticBag(); var block = (BoundBlock)binder.BindStatement(method.BlockSyntax, diagnostics); AssertEx.SetEqual(errors, diagnostics.AsEnumerable().Select(DumpDiagnostic)); }
public void TestErrors(string code, params string[] errors) { var compilation = CreateCompilationWithMscorlib(code); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var factory = compilation.GetBinderFactory(method.SyntaxTree); var bodyBlock = (BlockSyntax)method.BodySyntax; var parameterBinderContext = factory.GetBinder(bodyBlock); var binder = new ExecutableCodeBinder(bodyBlock.Parent, method, parameterBinderContext); var diagnostics = new DiagnosticBag(); var block = binder.BindEmbeddedBlock(bodyBlock, diagnostics); AssertEx.SetEqual(errors, diagnostics.AsEnumerable().Select(DumpDiagnostic)); }
public void TestErrors(string code, params string[] errors) { var compilation = CreateStandardCompilation(code); var method = (SourceMemberMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var factory = compilation.GetBinderFactory(method.SyntaxTree); var bodyBlock = (BlockSyntax)method.BodySyntax; var parameterBinderContext = factory.GetBinder(bodyBlock); var binder = new ExecutableCodeBinder(bodyBlock.Parent, method, parameterBinderContext); var diagnostics = new DiagnosticBag(); var block = binder.BindEmbeddedBlock(bodyBlock, diagnostics); AssertEx.SetEqual(errors, diagnostics.AsEnumerable().Select(DumpDiagnostic)); }
public void TestWarnings(string code, params string[] expectedWarnings) { var compilation = CreateCompilationWithMscorlib(code); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var factory = compilation.GetBinderFactory(method.SyntaxTree); var bodyBlock = (BlockSyntax)method.BodySyntax; var parameterBinderContext = factory.GetBinder(bodyBlock); var binder = new ExecutableCodeBinder(bodyBlock.Parent, method, parameterBinderContext); var block = (BoundBlock)binder.BindStatement(bodyBlock, new DiagnosticBag()); var actualWarnings = new DiagnosticBag(); DiagnosticsPass.IssueDiagnostics(compilation, block, actualWarnings, method); AssertEx.SetEqual(expectedWarnings, actualWarnings.AsEnumerable().Select(DumpDiagnostic)); }
private static BoundExpression BindFieldOrEnumInitializer( Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax initializer, DiagnosticBag diagnostics) { var enumConstant = fieldSymbol as SourceEnumConstantSymbol; Binder collisionDetector = new LocalScopeBinder(binder); collisionDetector = new ExecutableCodeBinder(initializer, fieldSymbol, collisionDetector); BoundExpression result; if ((object)enumConstant != null) { result = collisionDetector.BindEnumConstantInitializer(enumConstant, initializer, diagnostics); } else { result = collisionDetector.BindVariableOrAutoPropInitializer(initializer, RefKind.None, fieldSymbol.Type, diagnostics); } return result; }
private static BoundFieldEqualsValue BindFieldOrEnumInitializer( Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax initializer, BindingDiagnosticBag diagnostics) { var enumConstant = fieldSymbol as SourceEnumConstantSymbol; Binder collisionDetector = new LocalScopeBinder(binder); collisionDetector = new ExecutableCodeBinder(initializer, fieldSymbol, collisionDetector); BoundFieldEqualsValue result; if ((object)enumConstant != null) { result = collisionDetector.BindEnumConstantInitializer(enumConstant, initializer, diagnostics); } else { result = collisionDetector.BindFieldInitializer(fieldSymbol, initializer, diagnostics); } return(result); }
private static BoundExpression BindFieldOrEnumInitializer( Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax initializer, DiagnosticBag diagnostics) { var enumConstant = fieldSymbol as SourceEnumConstantSymbol; Binder collisionDetector = new LocalScopeBinder(binder); collisionDetector = new ExecutableCodeBinder(initializer, fieldSymbol, collisionDetector); BoundExpression result; if ((object)enumConstant != null) { result = collisionDetector.BindEnumConstantInitializer(enumConstant, initializer, diagnostics); } else { result = collisionDetector.BindVariableOrAutoPropInitializer(initializer, RefKind.None, fieldSymbol.Type, diagnostics); } return(result); }
public void TestWarnings(string code, params string[] expectedWarnings) { var compilation = CreateCompilationWithMscorlib(code); var method = (SourceMethodSymbol)compilation.GlobalNamespace.GetTypeMembers("C").Single().GetMembers("M").Single(); var factory = compilation.GetBinderFactory(method.SyntaxTree); var bodyBlock = (BlockSyntax)method.BodySyntax; var parameterBinderContext = factory.GetBinder(bodyBlock); var binder = new ExecutableCodeBinder(bodyBlock.Parent, method, parameterBinderContext); var block = (BoundBlock)binder.BindStatement(bodyBlock, new DiagnosticBag()); var actualWarnings = new DiagnosticBag(); DiagnosticsPass.IssueDiagnostics(compilation, block, actualWarnings, method); AssertEx.SetEqual(expectedWarnings, actualWarnings.AsEnumerable().Select(DumpDiagnostic)); }
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, diagnostics); lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, binder)); if (lambdaSymbol.RefKind == CodeAnalysis.RefKind.RefReadOnly) { binder.Compilation.EnsureIsReadOnlyAttributeExists(diagnostics, lambdaSymbol.DiagnosticLocation, modifyCompilationForRefReadOnly: false); } ParameterHelpers.EnsureIsReadOnlyAttributeExists(lambdaSymbol.Parameters, diagnostics, modifyCompilationForRefReadOnly: false); 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); SourceOrdinaryMethodSymbol.ReportAsyncParameterErrors(lambdaSymbol.Parameters, diagnostics, lambdaSymbol.DiagnosticLocation); } var result = new BoundLambda(_unboundLambda.Syntax, block, diagnostics.ToReadOnlyAndFree(), lambdaBodyBinder, delegateType, inferReturnType: false) { WasCompilerGenerated = _unboundLambda.WasCompilerGenerated }; return(result); }
/// <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? /// </remarks> private Binder GetLambdaEnclosingBinder(int position, SyntaxNode startingNode, SyntaxNode containingLambda, ExecutableCodeBinder lambdaBinder) { AssertPositionAdjusted(position); 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.IsInCatchClauseScope(position, (CatchClauseSyntax)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.Parent; } return lambdaBinder; }
/// <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? /// </remarks> private Binder GetLambdaEnclosingBinder(int position, SyntaxNode startingNode, SyntaxNode containingLambda, ExecutableCodeBinder lambdaBinder) { AssertPositionAdjusted(position); 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.IsInCatchClauseScope(position, (CatchClauseSyntax)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.Parent; } return(lambdaBinder); }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } if (methodNotType) { // Method locals and parameters shadow pseudo-variables. var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } binder = new EEMethodBinder(method, substitutedSourceMethod, binder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } binder = new ExecutableCodeBinder(syntax, binder.ContainingMemberOrLambda, binder); return binder; }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType, out ImmutableArray<LocalSymbol> declaredLocals) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } // Method locals and parameters shadow pseudo-variables. // That is why we place PlaceholderLocalBinder and ExecutableCodeBinder before EEMethodBinder. if (methodNotType) { var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } Binder originalRootBinder = null; SyntaxNode declaredLocalsScopeDesignator = null; var executableBinder = new ExecutableCodeBinder(syntax, substitutedSourceMethod, binder, (rootBinder, declaredLocalsScopeDesignatorOpt) => { originalRootBinder = rootBinder; declaredLocalsScopeDesignator = declaredLocalsScopeDesignatorOpt; binder = new EEMethodBinder(method, substitutedSourceMethod, rootBinder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }); // We just need to trigger the process of building the binder map // so that the lambda above was executed. executableBinder.GetBinder(syntax); Debug.Assert(originalRootBinder != null); Debug.Assert(executableBinder.Next != binder); if (declaredLocalsScopeDesignator != null) { declaredLocals = originalRootBinder.GetDeclaredLocalsForScope(declaredLocalsScopeDesignator); } else { declaredLocals = ImmutableArray<LocalSymbol>.Empty; } return binder; }