| File: Binder\WithLambdaParametersBinder.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { internal class WithLambdaParametersBinder : LocalScopeBinder { protected readonly LambdaSymbol lambdaSymbol; protected readonly MultiDictionary<string, ParameterSymbol> parameterMap; private readonly SmallDictionary<string, ParameterSymbol> _definitionMap; public WithLambdaParametersBinder(LambdaSymbol lambdaSymbol, Binder enclosing) : base(enclosing) { this.lambdaSymbol = lambdaSymbol; this.parameterMap = new MultiDictionary<string, ParameterSymbol>(); var parameters = lambdaSymbol.Parameters; if (!parameters.IsDefaultOrEmpty) { _definitionMap = new SmallDictionary<string, ParameterSymbol>(); foreach (var parameter in parameters) { if (!parameter.IsDiscard) { var name = parameter.Name; this.parameterMap.Add(name, parameter); if (!_definitionMap.ContainsKey(name)) { _definitionMap.Add(name, parameter); } } } } } protected override TypeSymbol GetCurrentReturnType(out RefKind refKind) { refKind = lambdaSymbol.RefKind; return lambdaSymbol.ReturnType; } internal override Symbol ContainingMemberOrLambda { get { return this.lambdaSymbol; } } internal override bool IsNestedFunctionBinder => true; internal override bool IsDirectlyInIterator { get { return false; } } // NOTE: Specifically not overriding IsIndirectlyInIterator. internal override TypeWithAnnotations GetIteratorElementType() { return TypeWithAnnotations.Create(CreateErrorType()); } protected override void ValidateYield(YieldStatementSyntax node, BindingDiagnosticBag diagnostics) { if (node != null) { diagnostics.Add(ErrorCode.ERR_YieldInAnonMeth, node.YieldKeyword.GetLocation()); } } internal override void LookupSymbolsInSingleBinder( LookupResult result, string name, int arity, ConsList<TypeSymbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo) { Debug.Assert(result.IsClear); if ((options & LookupOptions.NamespaceAliasesOnly) != 0) { return; } foreach (var parameterSymbol in parameterMap[name]) { result.MergeEqual(originalBinder.CheckViability(parameterSymbol, arity, options, null, diagnose, ref useSiteInfo)); } } internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (options.CanConsiderMembers()) { foreach (var parameter in lambdaSymbol.Parameters) { if (originalBinder.CanAddLookupSymbolInfo(parameter, options, result, null)) { result.AddSymbol(parameter, parameter.Name, 0); } } } } private static bool ReportConflictWithParameter(ParameterSymbol parameter, Symbol newSymbol, string name, Location newLocation, BindingDiagnosticBag diagnostics) { var oldLocation = parameter.GetFirstLocation(); if (oldLocation == newLocation) { // a query variable and its corresponding lambda parameter, for example return false; } // Quirk of the way we represent lambda parameters. SymbolKind newSymbolKind = (object)newSymbol == null ? SymbolKind.Parameter : newSymbol.Kind; switch (newSymbolKind) { case SymbolKind.ErrorType: return true; case SymbolKind.Parameter: case SymbolKind.Local: // Error: A local or parameter named '{0}' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter diagnostics.Add(ErrorCode.ERR_LocalIllegallyOverrides, newLocation, name); return true; case SymbolKind.Method: // Local function declaration name conflicts are not reported, for backwards compatibility. return false; case SymbolKind.TypeParameter: // Type parameter declaration name conflicts are not reported, for backwards compatibility. return false; case SymbolKind.RangeVariable: // The range variable '{0}' conflicts with a previous declaration of '{0}' diagnostics.Add(ErrorCode.ERR_QueryRangeVariableOverrides, newLocation, name); return true; } Debug.Assert(false, "what else could be defined in a lambda?"); diagnostics.Add(ErrorCode.ERR_InternalError, newLocation); return false; } internal override bool EnsureSingleDefinition(Symbol symbol, string name, Location location, BindingDiagnosticBag diagnostics) { ParameterSymbol existingDeclaration; var map = _definitionMap; if (map != null && map.TryGetValue(name, out existingDeclaration)) { return ReportConflictWithParameter(existingDeclaration, symbol, name, location, diagnostics); } return false; } internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(SyntaxNode scopeDesignator) { throw ExceptionUtilities.Unreachable(); } internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode scopeDesignator) { throw ExceptionUtilities.Unreachable(); } } }