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(); } }
public static MultiDictionary <Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node) { var emptyStructs = new CaptureWalkerEmptyStructTypeCache(); var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables); bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); var result = walker.variablesCaptured; 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. result.Add(method.ThisParameter, node.Syntax); } foreach (var variable in result.Keys.ToArray()) // take a snapshot, as we are modifying the underlying multidictionary { var local = variable as LocalSymbol; if ((object)local != null && local.RefKind != RefKind.None) { walker.AddSpillsForRef(walker.refLocalInitializers[local], result[local]); } } walker.Free(); return(result); }
// 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 : ((ParameterSymbol)variable).Type; 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); } } } if (compilation.Options.OptimizationLevel != OptimizationLevel.Release) { Debug.Assert(variablesToHoist.Count == 0); // In debug build we hoist all locals and parameters: foreach (var v in allVariables) { var symbol = v.Symbol; if ((object)symbol != null && HoistInDebugBuild(symbol)) { variablesToHoist.Add(symbol); } } } return(variablesToHoist); }
internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, EmptyStructTypeCache emptyStructCache = null) { var walker = new UnassignedVariablesWalker(compilation, member, node, emptyStructCache); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return badRegion ? new HashSet<Symbol>() : result; } finally { walker.Free(); } }
internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, EmptyStructTypeCache emptyStructCache = null) { var walker = new UnassignedVariablesWalker(compilation, member, node, emptyStructCache); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return(badRegion ? new HashSet <Symbol>() : result); } finally { walker.Free(); } }
// 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, 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 : ((ParameterSymbol)variable).Type; if (variable is SynthesizedLocal local && local.SynthesizedKind == SynthesizedLocalKind.Spill) { Debug.Assert(local.TypeWithAnnotations.IsRestrictedType()); diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, local.Locations[0], local.TypeWithAnnotations); } 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(); } }
public static MultiDictionary <Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node) { var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables); bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); var result = walker.variablesCaptured; 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. result.Add(method.ThisParameter, node.Syntax); } walker.Free(); return(result); }
private IteratorAndAsyncCaptureWalker(CSharpCompilation compilation, MethodSymbol method, BoundNode node, CaptureWalkerEmptyStructTypeCache emptyStructCache) : base(compilation, method, node, emptyStructCache, trackUnassignments: true, initiallyAssignedVariables: UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructCache)) { }