private ParameterSymbol GetLambdaParameterSymbol( ParameterSyntax parameter, ExpressionSyntax lambda, CancellationToken cancellationToken) { Debug.Assert(parameter != null); Debug.Assert(lambda != null && lambda.IsAnonymousFunction()); // We should always be able to get at least an error binding for a lambda. SymbolInfo symbolInfo = this.GetSymbolInfo(lambda, cancellationToken); LambdaSymbol lambdaSymbol; if ((object)symbolInfo.Symbol != null) { lambdaSymbol = (LambdaSymbol)symbolInfo.Symbol; } else if (symbolInfo.CandidateSymbols.Length == 1) { lambdaSymbol = (LambdaSymbol)symbolInfo.CandidateSymbols.Single(); } else { Debug.Assert(this.GetMemberModel(lambda) == null, "Did not find a unique LambdaSymbol for lambda in member."); return null; } return GetParameterSymbol(lambdaSymbol.Parameters, parameter, cancellationToken); }
public override Conversion ClassifyConversion( ExpressionSyntax expression, ITypeSymbol destination, bool isExplicitInSource = false) { if ((object)destination == null) { throw new ArgumentNullException(nameof(destination)); } var csdestination = destination.EnsureCSharpSymbolOrNull<ITypeSymbol, TypeSymbol>("destination"); // Special Case: We have to treat anonymous functions differently, because of the way // they are cached in the syntax-to-bound node map. Specifically, UnboundLambda nodes // never appear in the map - they are converted to BoundLambdas, even in error scenarios. // Since a BoundLambda has a type, we would end up doing a conversion from the delegate // type, rather than from the anonymous function expression. If we use the overload that // takes a position, it considers the request speculative and does not use the map. // Bonus: Since the other overload will always bind the anonymous function from scratch, // we don't have to worry about it affecting the trial-binding cache in the "real" // UnboundLambda node (DevDiv #854548). if (expression.IsAnonymousFunction()) { CheckSyntaxNode(expression); return this.ClassifyConversion(expression.SpanStart, expression, destination, isExplicitInSource); } if (isExplicitInSource) { return ClassifyConversionForCast(expression, csdestination); } // Note that it is possible for an expression to be convertible to a type // via both an implicit user-defined conversion and an explicit built-in conversion. // In that case, this method chooses the implicit conversion. CheckSyntaxNode(expression); var binder = this.GetEnclosingBinder(expression, GetAdjustedNodePosition(expression)); CSharpSyntaxNode bindableNode = this.GetBindableSyntaxNode(expression); var boundExpression = this.GetLowerBoundNode(bindableNode) as BoundExpression; if (binder == null || boundExpression == null) { return Conversion.NoConversion; } HashSet<DiagnosticInfo> useSiteDiagnostics = null; return binder.Conversions.ClassifyConversionFromExpression(boundExpression, csdestination, ref useSiteDiagnostics); }