// Returns deterministically ordered list of variables that ought to be hoisted. public static OrderedSet <Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics) { var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables); walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct) { // It is possible that the enclosing method only *writes* to the enclosing struct, but in that // case it should be considered captured anyway so that we have a proxy for it to write to. walker.CaptureVariable(method.ThisParameter, node.Syntax); } var variablesToHoist = walker._variablesToHoist; var lazyDisallowedCaptures = walker._lazyDisallowedCaptures; var allVariables = walker.variableBySlot; walker.Free(); if (lazyDisallowedCaptures != null) { foreach (var kvp in lazyDisallowedCaptures) { var variable = kvp.Key; var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type.TypeSymbol : ((ParameterSymbol)variable).Type.TypeSymbol; if (variable is SynthesizedLocal local && local.SynthesizedKind == SynthesizedLocalKind.Spill) { Debug.Assert(local.Type.IsRestrictedType()); diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, local.Locations[0], local.Type); } else { foreach (CSharpSyntaxNode syntax in kvp.Value) { // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type); } } }
internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, bool convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false) { var walker = new UnassignedVariablesWalker(compilation, member, node); if (convertInsufficientExecutionStackExceptionToCancelledByStackGuardException) { walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; } try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return(badRegion ? new HashSet <Symbol>() : result); } finally { walker.Free(); } }