77using System . Collections . Immutable ;
88using System . Diagnostics ;
99using System . Linq ;
10+ using Microsoft . CodeAnalysis . Collections ;
1011using Microsoft . CodeAnalysis . CSharp . Symbols ;
1112using Microsoft . CodeAnalysis . PooledObjects ;
1213using Roslyn . Utilities ;
@@ -61,7 +62,7 @@ private static bool InUnsafeMethod(Symbol symbol)
6162 private bool _inUnsafeRegion ;
6263 private SafeContext _localScopeDepth ;
6364 private Dictionary < LocalSymbol , ( SafeContext RefEscapeScope , SafeContext ValEscapeScope ) > ? _localEscapeScopes ;
64- private Dictionary < BoundValuePlaceholderBase , SafeContext > ? _placeholderScopes ;
65+ private KeyedStack < BoundValuePlaceholderBase , SafeContext > ? _placeholderScopes ;
6566 private SafeContext _patternInputValEscape ;
6667#if DEBUG
6768 private const int MaxTrackVisited = 100 ; // Avoid tracking if too many expressions.
@@ -152,22 +153,24 @@ private ref struct PlaceholderRegion
152153 {
153154 private readonly RefSafetyAnalysis _analysis ;
154155 private readonly ArrayBuilder < ( BoundValuePlaceholderBase , SafeContext ) > _placeholders ;
156+ private readonly bool _overwriteExistingTemporarily ;
155157
156- public PlaceholderRegion ( RefSafetyAnalysis analysis , ArrayBuilder < ( BoundValuePlaceholderBase , SafeContext ) > placeholders )
158+ public PlaceholderRegion ( RefSafetyAnalysis analysis , ArrayBuilder < ( BoundValuePlaceholderBase , SafeContext ) > placeholders , bool overwriteExistingTemporarily = false )
157159 {
158160 _analysis = analysis ;
159161 _placeholders = placeholders ;
162+ _overwriteExistingTemporarily = overwriteExistingTemporarily ;
160163 foreach ( var ( placeholder , valEscapeScope ) in placeholders )
161164 {
162- _analysis . AddPlaceholderScope ( placeholder , valEscapeScope ) ;
165+ _analysis . AddPlaceholderScope ( placeholder , valEscapeScope , canExist : overwriteExistingTemporarily ) ;
163166 }
164167 }
165168
166169 public void Dispose ( )
167170 {
168171 foreach ( var ( placeholder , _) in _placeholders )
169172 {
170- _analysis . RemovePlaceholderScope ( placeholder ) ;
173+ _analysis . RemovePlaceholderScope ( placeholder , forcePop : _overwriteExistingTemporarily ) ;
171174 }
172175 _placeholders . Free ( ) ;
173176 }
@@ -189,33 +192,34 @@ private void SetLocalScopes(LocalSymbol local, SafeContext refEscapeScope, SafeC
189192 AddOrSetLocalScopes ( local , refEscapeScope , valEscapeScope ) ;
190193 }
191194
192- private void AddPlaceholderScope ( BoundValuePlaceholderBase placeholder , SafeContext valEscapeScope )
195+ private void AddPlaceholderScope ( BoundValuePlaceholderBase placeholder , SafeContext valEscapeScope , bool canExist = false )
193196 {
194- Debug . Assert ( _placeholderScopes ? . ContainsKey ( placeholder ) != true ) ;
197+ Debug . Assert ( canExist || _placeholderScopes ? . ContainsKey ( placeholder ) != true ) ;
195198
196199 // Consider not adding the placeholder to the dictionary if the escape scope is
197200 // CallingMethod, and simply fallback to that value in GetPlaceholderScope().
198201
199- _placeholderScopes ??= new Dictionary < BoundValuePlaceholderBase , SafeContext > ( ) ;
200- _placeholderScopes [ placeholder ] = valEscapeScope ;
202+ _placeholderScopes ??= new KeyedStack < BoundValuePlaceholderBase , SafeContext > ( ) ;
203+ _placeholderScopes . Push ( placeholder , valEscapeScope ) ;
201204 }
202205
203- #pragma warning disable IDE0060
204- private void RemovePlaceholderScope ( BoundValuePlaceholderBase placeholder )
206+ private void RemovePlaceholderScope ( BoundValuePlaceholderBase placeholder , bool forcePop = false )
205207 {
206208 Debug . Assert ( _placeholderScopes ? . ContainsKey ( placeholder ) == true ) ;
207209
208210 // https://github.com/dotnet/roslyn/issues/65961: Currently, analysis may require subsequent calls
209211 // to GetRefEscape(), etc. for the same expression so we cannot remove placeholders eagerly.
210- //_placeholderScopes.Remove(placeholder);
212+ if ( forcePop )
213+ {
214+ _placeholderScopes ? . TryPop ( placeholder , out _ ) ;
215+ }
211216 }
212- #pragma warning restore IDE0060
213217
214218 private SafeContext GetPlaceholderScope ( BoundValuePlaceholderBase placeholder )
215219 {
216220 Debug . Assert ( _placeholderScopes ? . ContainsKey ( placeholder ) == true ) ;
217221
218- return _placeholderScopes ? . TryGetValue ( placeholder , out var scope ) == true
222+ return _placeholderScopes ? . TryPeek ( placeholder , out var scope ) == true
219223 ? scope
220224 : SafeContext . CallingMethod ;
221225 }
0 commit comments