Files
2026-08-27 10:56:38 -06:00

423 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp;
internal sealed class IteratorAndAsyncCaptureWalker : DefiniteAssignmentPass
{
private sealed class OutsideVariablesUsedInside : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
{
private readonly HashSet<Symbol> _localsInScope;
private readonly IteratorAndAsyncCaptureWalker _analyzer;
private readonly MethodSymbol _topLevelMethod;
private readonly IteratorAndAsyncCaptureWalker _parent;
public OutsideVariablesUsedInside(IteratorAndAsyncCaptureWalker analyzer, MethodSymbol topLevelMethod, IteratorAndAsyncCaptureWalker parent)
: base(parent._recursionDepth)
{
_analyzer = analyzer;
_topLevelMethod = topLevelMethod;
_localsInScope = new HashSet<Symbol>();
_parent = parent;
}
protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException()
{
return _parent.ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException();
}
public override BoundNode VisitBlock(BoundBlock node)
{
AddVariables(node.Locals);
return base.VisitBlock(node);
}
private void AddVariables(ImmutableArray<LocalSymbol> locals)
{
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
while (enumerator.MoveNext())
{
LocalSymbol current = enumerator.Current;
AddVariable(current);
}
}
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
AddVariables(node.Locals);
return base.VisitCatchBlock(node);
}
private void AddVariable(Symbol local)
{
if ((object)local != null)
{
_localsInScope.Add(local);
}
}
public override BoundNode VisitSequence(BoundSequence node)
{
AddVariables(node.Locals);
return base.VisitSequence(node);
}
public override BoundNode VisitThisReference(BoundThisReference node)
{
Capture(_topLevelMethod.ThisParameter, node.Syntax);
return base.VisitThisReference(node);
}
public override BoundNode VisitBaseReference(BoundBaseReference node)
{
Capture(_topLevelMethod.ThisParameter, node.Syntax);
return base.VisitBaseReference(node);
}
public override BoundNode VisitLocal(BoundLocal node)
{
Capture(node.LocalSymbol, node.Syntax);
return base.VisitLocal(node);
}
public override BoundNode VisitParameter(BoundParameter node)
{
Capture(node.ParameterSymbol, node.Syntax);
return base.VisitParameter(node);
}
private void Capture(Symbol s, SyntaxNode syntax)
{
if ((object)s != null && !_localsInScope.Contains(s))
{
_analyzer.CaptureVariable(s, syntax);
}
}
}
private readonly OrderedSet<Symbol> _variablesToHoist = new OrderedSet<Symbol>();
private MultiDictionary<Symbol, SyntaxNode> _lazyDisallowedCaptures;
private bool _seenYieldInCurrentTry;
private readonly Dictionary<LocalSymbol, BoundExpression> _boundRefLocalInitializers = new Dictionary<LocalSymbol, BoundExpression>();
private IteratorAndAsyncCaptureWalker(CSharpCompilation compilation, MethodSymbol method, BoundNode node, HashSet<Symbol> initiallyAssignedVariables)
: base(compilation, method, node, EmptyStructTypeCache.CreateNeverEmpty(), trackUnassignments: true, initiallyAssignedVariables)
{
}
public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Invalid comparison between Unknown and I4
//IL_0177: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Invalid comparison between Unknown and I4
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Invalid comparison between Unknown and I4
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Invalid comparison between Unknown and I4
HashSet<Symbol> hashSet = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true);
IteratorAndAsyncCaptureWalker iteratorAndAsyncCaptureWalker = new IteratorAndAsyncCaptureWalker(compilation, method, node, hashSet);
iteratorAndAsyncCaptureWalker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true;
bool badRegion = false;
iteratorAndAsyncCaptureWalker.Analyze(ref badRegion);
if (!method.IsStatic && (int)method.ContainingType.TypeKind == 10)
{
iteratorAndAsyncCaptureWalker.CaptureVariable(method.ThisParameter, node.Syntax);
}
MultiDictionary<Symbol, SyntaxNode> lazyDisallowedCaptures = iteratorAndAsyncCaptureWalker._lazyDisallowedCaptures;
ArrayBuilder<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier> val = iteratorAndAsyncCaptureWalker.variableBySlot;
if (lazyDisallowedCaptures != null)
{
foreach (KeyValuePair<Symbol, ValueSet<Symbol, SyntaxNode>> item in lazyDisallowedCaptures)
{
Symbol key = item.Key;
TypeSymbol typeSymbol = (((int)key.Kind == 8) ? ((LocalSymbol)key).Type : ((ParameterSymbol)key).Type);
if (key is SynthesizedLocal synthesizedLocal && (int)synthesizedLocal.SynthesizedKind == 28)
{
diagnostics.Add(ErrorCode.ERR_ByRefTypeAndAwait, synthesizedLocal.GetFirstLocation(), synthesizedLocal.TypeWithAnnotations);
continue;
}
Enumerator<Symbol, SyntaxNode> enumerator2 = item.Value.GetEnumerator();
try
{
while (enumerator2.MoveNext())
{
CSharpSyntaxNode cSharpSyntaxNode = (CSharpSyntaxNode)(object)enumerator2.Current;
diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, ((SyntaxNode)cSharpSyntaxNode).Location, typeSymbol);
}
}
finally
{
((IDisposable)enumerator2/*cast due to constrained. prefix*/).Dispose();
}
}
}
OrderedSet<Symbol> val2 = new OrderedSet<Symbol>();
if ((int)((CompilationOptions)compilation.Options).OptimizationLevel != 1)
{
Enumerator<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier> enumerator3 = val.GetEnumerator();
while (enumerator3.MoveNext())
{
Symbol symbol = enumerator3.Current.Symbol;
if ((object)symbol != null && HoistInDebugBuild(symbol))
{
val2.Add(symbol);
}
}
}
val2.AddRange((IEnumerable<Symbol>)iteratorAndAsyncCaptureWalker._variablesToHoist);
iteratorAndAsyncCaptureWalker.Free();
return val2;
}
private static bool HoistInDebugBuild(Symbol symbol)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
if (!(symbol is ParameterSymbol parameterSymbol))
{
if (symbol is LocalSymbol { IsConst: false, IsPinned: false, IsRef: false } localSymbol)
{
return SynthesizedLocalKindExtensions.MustSurviveStateMachineSuspension(localSymbol.SynthesizedKind) && !localSymbol.Type.IsRestrictedType();
}
return false;
}
return !parameterSymbol.Type.IsRestrictedType();
}
private void MarkLocalsUnassigned()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Invalid comparison between Unknown and I4
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Invalid comparison between Unknown and I4
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Invalid comparison between Unknown and I4
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < variableBySlot.Count; i++)
{
Symbol symbol = variableBySlot[i].Symbol;
if ((object)symbol == null)
{
continue;
}
SymbolKind kind = symbol.Kind;
if ((int)kind != 6)
{
if ((int)kind != 8)
{
if ((int)kind != 13)
{
throw ExceptionUtilities.UnexpectedValue((object)symbol.Kind);
}
SetSlotState(i, assigned: false);
}
else if (!((LocalSymbol)symbol).IsConst)
{
SetSlotState(i, assigned: false);
}
}
else if (!((FieldSymbol)symbol).IsConst)
{
SetSlotState(i, assigned: false);
}
}
}
public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
{
base.VisitAwaitExpression(node);
MarkLocalsUnassigned();
return null;
}
public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement node)
{
base.VisitYieldReturnStatement(node);
MarkLocalsUnassigned();
_seenYieldInCurrentTry = true;
return null;
}
protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
{
_variablesToHoist.Clear();
_lazyDisallowedCaptures?.Clear();
return base.Scan(ref badRegion);
}
private void CaptureVariable(Symbol variable, SyntaxNode syntax)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
BoundExpression value;
if ((((int)variable.Kind == 8) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type).IsRestrictedType())
{
(_lazyDisallowedCaptures ?? (_lazyDisallowedCaptures = new MultiDictionary<Symbol, SyntaxNode>())).Add(variable, syntax);
}
else if (_variablesToHoist.Add(variable) && variable is LocalSymbol key && _boundRefLocalInitializers.TryGetValue(key, out value))
{
CaptureRefInitializer(value, syntax);
}
}
private void CaptureRefInitializer(BoundExpression variableInitializer, SyntaxNode syntax)
{
if (variableInitializer is BoundLocal boundLocal)
{
LocalSymbol localSymbol = boundLocal.LocalSymbol;
CaptureVariable(localSymbol, syntax);
}
else if (variableInitializer is BoundParameter boundParameter)
{
ParameterSymbol parameterSymbol = boundParameter.ParameterSymbol;
CaptureVariable(parameterSymbol, syntax);
}
else
{
if (!(variableInitializer is BoundFieldAccess boundFieldAccess))
{
return;
}
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
if ((object)fieldSymbol == null || fieldSymbol.IsStatic)
{
return;
}
NamedTypeSymbol containingType = fieldSymbol.ContainingType;
if ((object)containingType != null && containingType.IsValueType)
{
BoundExpression receiverOpt = boundFieldAccess.ReceiverOpt;
if (receiverOpt != null)
{
CaptureRefInitializer(receiverOpt, syntax);
}
}
}
}
protected override void EnterParameter(ParameterSymbol parameter)
{
GetOrCreateSlot(parameter);
}
protected override void ReportUnassigned(Symbol symbol, SyntaxNode node, int slot, bool skipIfUseBeforeDeclaration)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Invalid comparison between Unknown and I4
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Invalid comparison between Unknown and I4
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
SymbolKind kind = symbol.Kind;
if ((int)kind != 6)
{
if ((int)kind != 8 && (int)kind != 13)
{
return;
}
}
else
{
symbol = GetNonMemberSymbol(slot);
}
CaptureVariable(symbol, node);
}
protected override void VisitLvalueParameter(BoundParameter node)
{
TryHoistTopLevelParameter(node);
base.VisitLvalueParameter(node);
}
public override BoundNode VisitParameter(BoundParameter node)
{
TryHoistTopLevelParameter(node);
return base.VisitParameter(node);
}
private void TryHoistTopLevelParameter(BoundParameter node)
{
if (node.ParameterSymbol.ContainingSymbol == topLevelMethod)
{
CaptureVariable(node.ParameterSymbol, node.Syntax);
}
}
public override BoundNode VisitFieldAccess(BoundFieldAccess node)
{
if (node.ReceiverOpt != null && node.ReceiverOpt.Kind == BoundKind.ThisReference)
{
ParameterSymbol thisParameter = topLevelMethod.ThisParameter;
CaptureVariable(thisParameter, node.Syntax);
}
return base.VisitFieldAccess(node);
}
public override BoundNode VisitThisReference(BoundThisReference node)
{
CaptureVariable(topLevelMethod.ThisParameter, node.Syntax);
return base.VisitThisReference(node);
}
public override BoundNode VisitBaseReference(BoundBaseReference node)
{
CaptureVariable(topLevelMethod.ThisParameter, node.Syntax);
return base.VisitBaseReference(node);
}
public override BoundNode VisitTryStatement(BoundTryStatement node)
{
bool seenYieldInCurrentTry = _seenYieldInCurrentTry;
_seenYieldInCurrentTry = false;
base.VisitTryStatement(node);
_seenYieldInCurrentTry |= seenYieldInCurrentTry;
return null;
}
protected override void VisitFinallyBlock(BoundStatement finallyBlock, ref LocalState unsetInFinally)
{
if (_seenYieldInCurrentTry)
{
new OutsideVariablesUsedInside(this, topLevelMethod, this).Visit(finallyBlock);
}
base.VisitFinallyBlock(finallyBlock, ref unsetInFinally);
}
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
base.VisitAssignmentOperator(node);
if (node != null && node.IsRef && node.Left is BoundLocal boundLocal)
{
LocalSymbol localSymbol = boundLocal.LocalSymbol;
if ((object)localSymbol != null && localSymbol.IsCompilerGenerated)
{
_boundRefLocalInitializers[localSymbol] = node.Right;
}
}
return null;
}
}