Skip to content

Commit da69bef

Browse files
committed
Extensions: ref safety analysis
1 parent 554fe0e commit da69bef

File tree

2 files changed

+354
-16
lines changed

2 files changed

+354
-16
lines changed

src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Collections.Immutable;
88
using System.Diagnostics;
99
using System.Diagnostics.CodeAnalysis;
10-
using Microsoft.CodeAnalysis.CSharp.CodeGen;
1110
using Microsoft.CodeAnalysis.CSharp.Symbols;
1211
using Microsoft.CodeAnalysis.PooledObjects;
1312
using Roslyn.Utilities;
@@ -2253,7 +2252,8 @@ private bool CheckInvocationEscapeWithUpdatedRules(
22532252
// For consistency with C#10 implementation, we don't report an additional error
22542253
// for the receiver. (In both implementations, the call to Check*Escape() above
22552254
// will have reported a specific escape error for the receiver though.)
2256-
if ((object)((argument as BoundCapturedReceiverPlaceholder)?.Receiver ?? argument) != receiver && symbol is not SignatureOnlyMethodSymbol)
2255+
bool argumentIsReceiver = (object)((argument as BoundCapturedReceiverPlaceholder)?.Receiver ?? argument) == receiver;
2256+
if ((!argumentIsReceiver || param?.IsExtensionParameter() == true) && symbol is not SignatureOnlyMethodSymbol)
22572257
{
22582258
ReportInvocationEscapeError(syntax, symbol, param, checkingReceiver, diagnostics);
22592259
}
@@ -2289,25 +2289,46 @@ private void GetInvocationArgumentsForEscape(
22892289
{
22902290
if (receiver is { })
22912291
{
2292-
Debug.Assert(receiver.Type is { });
2293-
Debug.Assert(receiverIsSubjectToCloning != ThreeState.Unknown);
2294-
var method = methodInfo.Method;
2295-
if (receiverIsSubjectToCloning == ThreeState.True)
2292+
MethodSymbol? method = methodInfo.Method;
2293+
if (method?.GetIsNewExtensionMember() == true)
22962294
{
2297-
Debug.Assert(receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type?.IsReferenceType == false);
2295+
// Analyze the receiver as an argument
2296+
var parameter = method.ContainingType.ExtensionParameter;
2297+
2298+
if (mixableArguments is not null
2299+
&& isMixableParameter(parameter)
2300+
// assume any expression variable is a valid mixing destination,
2301+
// since we will infer a legal val-escape for it (if it doesn't already have a narrower one).
2302+
&& isMixableArgument(receiver))
2303+
{
2304+
mixableArguments.Add(new MixableDestination(parameter, receiver));
2305+
}
2306+
2307+
var refKind = parameter?.RefKind ?? RefKind.None;
2308+
2309+
escapeArguments.Add(new EscapeArgument(parameter, receiver, refKind));
2310+
}
2311+
else
2312+
{
2313+
Debug.Assert(receiver.Type is { });
2314+
Debug.Assert(receiverIsSubjectToCloning != ThreeState.Unknown);
2315+
if (receiverIsSubjectToCloning == ThreeState.True)
2316+
{
2317+
Debug.Assert(receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type?.IsReferenceType == false);
22982318
#if DEBUG
2299-
AssertVisited(receiver);
2319+
AssertVisited(receiver);
23002320
#endif
2301-
// Equivalent to a non-ref local with the underlying receiver as an initializer provided at declaration
2302-
receiver = new BoundCapturedReceiverPlaceholder(receiver.Syntax, receiver, _localScopeDepth, receiver.Type).MakeCompilerGenerated();
2303-
}
2321+
// Equivalent to a non-ref local with the underlying receiver as an initializer provided at declaration
2322+
receiver = new BoundCapturedReceiverPlaceholder(receiver.Syntax, receiver, _localScopeDepth, receiver.Type).MakeCompilerGenerated();
2323+
}
23042324

2305-
var tuple = getReceiver(methodInfo, receiver);
2306-
escapeArguments.Add(tuple);
2325+
var tuple = getReceiver(methodInfo, receiver);
2326+
escapeArguments.Add(tuple);
23072327

2308-
if (mixableArguments is not null && isMixableParameter(tuple.Parameter))
2309-
{
2310-
mixableArguments.Add(new MixableDestination(tuple.Parameter, receiver));
2328+
if (mixableArguments is not null && isMixableParameter(tuple.Parameter))
2329+
{
2330+
mixableArguments.Add(new MixableDestination(tuple.Parameter, receiver));
2331+
}
23112332
}
23122333
}
23132334

0 commit comments

Comments
 (0)