private void ComputeBinderMap() { SmallDictionary <SyntaxNode, Binder> map; ImmutableArray <MethodSymbol> methodSymbolsWithYield; // Ensure that the member symbol is a method symbol. if ((object)_memberSymbol != null && _root != null) { var methodsWithYield = ArrayBuilder <SyntaxNode> .GetInstance(); var symbolsWithYield = ArrayBuilder <MethodSymbol> .GetInstance(); map = LocalBinderFactory.BuildMap(_memberSymbol, _root, this, methodsWithYield, _binderUpdatedHandler); foreach (var methodWithYield in methodsWithYield) { Binder binder = this; if (methodWithYield.Kind() != SyntaxKind.GlobalStatement && (methodWithYield == _root || map.TryGetValue(methodWithYield, out binder))) { Symbol containing = binder.ContainingMemberOrLambda; // get the closest enclosing InMethodBinder and make it an iterator InMethodBinder inMethod = null; while (binder != null) { inMethod = binder as InMethodBinder; if (inMethod != null) { break; } binder = binder.Next; } if (inMethod != null && (object)inMethod.ContainingMemberOrLambda == containing) { inMethod.MakeIterator(); symbolsWithYield.Add((MethodSymbol)inMethod.ContainingMemberOrLambda); } else { Debug.Assert(methodWithYield == _root && methodWithYield is ExpressionSyntax); } } else { // skip over it, this is an error } } methodsWithYield.Free(); methodSymbolsWithYield = symbolsWithYield.ToImmutableAndFree(); } else { map = SmallDictionary <SyntaxNode, Binder> .Empty; methodSymbolsWithYield = ImmutableArray <MethodSymbol> .Empty; } Interlocked.CompareExchange(ref _lazyBinderMap, map, null); ImmutableInterlocked.InterlockedCompareExchange(ref _methodSymbolsWithYield, methodSymbolsWithYield, default(ImmutableArray <MethodSymbol>)); }
// methodsWithYields will contain all function-declaration-like CSharpSyntaxNodes with yield statements contained within them. // Currently the types of these are restricted to only be whatever the syntax parameter is, plus any LocalFunctionStatementSyntax contained within it. // This may change if the language is extended to allow iterator lambdas, in which case the lambda would also be returned. // (lambdas currently throw a diagnostic in WithLambdaParametersBinder.GetIteratorElementType when a yield is used within them) public static SmallDictionary <SyntaxNode, Binder> BuildMap( Symbol containingMemberOrLambda, SyntaxNode syntax, Binder enclosing, ArrayBuilder <SyntaxNode> methodsWithYields, Action <Binder, SyntaxNode> binderUpdatedHandler = null) { var builder = new LocalBinderFactory(containingMemberOrLambda, syntax, enclosing, methodsWithYields); StatementSyntax statement; var expressionSyntax = syntax as ExpressionSyntax; if (expressionSyntax != null) { enclosing = new ExpressionVariableBinder(syntax, enclosing); if ((object)binderUpdatedHandler != null) { binderUpdatedHandler(enclosing, syntax); } builder.AddToMap(syntax, enclosing); builder.Visit(expressionSyntax, enclosing); } else if (syntax.Kind() != SyntaxKind.Block && (statement = syntax as StatementSyntax) != null) { CSharpSyntaxNode embeddedScopeDesignator; enclosing = builder.GetBinderForPossibleEmbeddedStatement(statement, enclosing, out embeddedScopeDesignator); if ((object)binderUpdatedHandler != null) { binderUpdatedHandler(enclosing, embeddedScopeDesignator); } if (embeddedScopeDesignator != null) { builder.AddToMap(embeddedScopeDesignator, enclosing); } builder.Visit(statement, enclosing); } else { if ((object)binderUpdatedHandler != null) { binderUpdatedHandler(enclosing, null); } builder.Visit((CSharpSyntaxNode)syntax, enclosing); } // the other place this is possible is in a local function if (builder._sawYield) { methodsWithYields.Add(syntax); } return(builder._map); }