// 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); } } }
protected BoundStatement Rewrite() { if (this.body.HasErrors) { return(this.body); } F.OpenNestedType(stateMachineType); GenerateControlFields(); if (PreserveInitialParameterValuesAndThreadId && CanGetThreadId()) { // if it is an enumerable or async-enumerable, and either Environment.CurrentManagedThreadId or Thread.ManagedThreadId are available // add a field: int initialThreadId initialThreadIdField = F.StateMachineField(F.SpecialType(SpecialType.System_Int32), GeneratedNames.MakeIteratorCurrentThreadIdFieldName()); } // fields for the initial values of all the parameters of the method if (PreserveInitialParameterValuesAndThreadId) { initialParameters = new Dictionary <Symbol, CapturedSymbolReplacement>(); } // fields for the captured variables of the method var variablesToHoist = IteratorAndAsyncCaptureWalker.Analyze(F.Compilation, method, body, diagnostics); CreateNonReusableLocalProxies(variablesToHoist, out this.nonReusableLocalProxies, out this.nextFreeHoistedLocalSlot); this.hoistedVariables = variablesToHoist; GenerateMethodImplementations(); // Return a replacement body for the kickoff method return(GenerateKickoffMethodBody()); }