Skip to content

Commit ad4b0f8

Browse files
Merge remote-tracking branch 'upstream/main' into spellCheckingSnippet
2 parents f7067fd + e4667d4 commit ad4b0f8

File tree

4 files changed

+61
-496
lines changed

4 files changed

+61
-496
lines changed

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

Lines changed: 20 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,11 +1943,7 @@ private static void GetInvocationArgumentsForEscape(
19431943
parameters[argsToParamsOpt.IsDefault ? argIndex : argsToParamsOpt[argIndex]] :
19441944
null;
19451945

1946-
if (mixableArguments is not null
1947-
&& isMixableParameter(parameter)
1948-
// assume any expression variable is a valid mixing destination,
1949-
// since we will infer a legal val-escape for it (if it doesn't already have a narrower one).
1950-
&& isMixableArgument(argument))
1946+
if (mixableArguments is not null && isMixableParameter(parameter))
19511947
{
19521948
mixableArguments.Add(new MixableDestination(parameter, argument));
19531949
}
@@ -1972,9 +1968,6 @@ parameter is not null &&
19721968
parameter.Type.IsRefLikeType &&
19731969
parameter.RefKind.IsWritableReference();
19741970

1975-
static bool isMixableArgument(BoundExpression argument) =>
1976-
argument is not (BoundDeconstructValuePlaceholder or BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None });
1977-
19781971
static EscapeArgument getReceiver(Symbol symbol, BoundExpression receiver)
19791972
{
19801973
if (symbol is FunctionPointerMethodSymbol)
@@ -2202,30 +2195,6 @@ private bool UseUpdatedEscapeRulesForInvocation(Symbol symbol)
22022195
return method?.UseUpdatedEscapeRules == true;
22032196
}
22042197

2205-
private static bool ShouldInferDeclarationExpressionValEscape(BoundExpression argument, [NotNullWhen(true)] out SourceLocalSymbol? localSymbol)
2206-
{
2207-
var symbol = argument switch
2208-
{
2209-
BoundDeconstructValuePlaceholder p => p.ExpressionSymbol,
2210-
BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None } l => l.ExpressionSymbol,
2211-
_ => null
2212-
};
2213-
if (symbol is SourceLocalSymbol { ValEscapeScope: CallingMethodScope } local)
2214-
{
2215-
localSymbol = local;
2216-
return true;
2217-
}
2218-
else
2219-
{
2220-
// No need to infer a val escape for a global variable.
2221-
// These are only used in top-level statements in scripting mode,
2222-
// and since they are class fields, their scope is always CallingMethod.
2223-
Debug.Assert(symbol is null or SourceLocalSymbol or GlobalExpressionVariable);
2224-
localSymbol = null;
2225-
return false;
2226-
}
2227-
}
2228-
22292198
/// <summary>
22302199
/// Validates whether the invocation is valid per no-mixing rules.
22312200
/// Returns <see langword="false"/> when it is not valid and produces diagnostics (possibly more than one recursively) that helps to figure the reason.
@@ -2270,7 +2239,7 @@ private bool CheckInvocationArgMixing(
22702239
var escapeArguments = ArrayBuilder<EscapeArgument>.GetInstance();
22712240
GetInvocationArgumentsForEscape(
22722241
symbol,
2273-
receiverOpt,
2242+
receiver: null, // receiver handled explicitly below
22742243
parameters,
22752244
argsOpt,
22762245
argRefKindsOpt: default,
@@ -2283,51 +2252,43 @@ private bool CheckInvocationArgMixing(
22832252
{
22842253
foreach (var (_, argument, refKind) in escapeArguments)
22852254
{
2286-
if (ShouldInferDeclarationExpressionValEscape(argument, out _))
2287-
{
2288-
// assume any expression variable is a valid mixing destination,
2289-
// since we will infer a legal val-escape for it (if it doesn't already have a narrower one).
2290-
continue;
2291-
}
2292-
22932255
if (refKind.IsWritableReference() && argument.Type?.IsRefLikeType == true)
22942256
{
22952257
escapeTo = Math.Min(escapeTo, GetValEscape(argument, scopeOfTheContainingExpression));
22962258
}
22972259
}
22982260

2299-
var hasMixingError = false;
2261+
if (escapeTo == scopeOfTheContainingExpression)
2262+
{
2263+
// cannot fail. common case.
2264+
return true;
2265+
}
23002266

2301-
// track the widest scope that arguments could safely escape to.
2302-
// use this scope as the inferred STE of declaration expressions.
2303-
var inferredDestinationValEscape = CallingMethodScope;
23042267
foreach (var (parameter, argument, _) in escapeArguments)
23052268
{
2306-
// in the old rules, we assume that refs cannot escape into ref struct variables.
2307-
// e.g. in `dest = M(ref arg)`, we assume `ref arg` will not escape into `dest`, but `arg` might.
2308-
inferredDestinationValEscape = Math.Max(inferredDestinationValEscape, GetValEscape(argument, scopeOfTheContainingExpression));
2309-
if (!hasMixingError && !CheckValEscape(argument.Syntax, argument, scopeOfTheContainingExpression, escapeTo, false, diagnostics))
2269+
var valid = CheckValEscape(argument.Syntax, argument, scopeOfTheContainingExpression, escapeTo, false, diagnostics);
2270+
2271+
if (!valid)
23102272
{
23112273
string parameterName = GetInvocationParameterName(parameter);
23122274
Error(diagnostics, ErrorCode.ERR_CallArgMixing, syntax, symbol, parameterName);
2313-
hasMixingError = true;
2314-
}
2315-
}
2316-
2317-
foreach (var (_, argument, _) in escapeArguments)
2318-
{
2319-
if (ShouldInferDeclarationExpressionValEscape(argument, out var localSymbol))
2320-
{
2321-
localSymbol.SetValEscape(inferredDestinationValEscape);
2275+
return false;
23222276
}
23232277
}
2324-
2325-
return !hasMixingError;
23262278
}
23272279
finally
23282280
{
23292281
escapeArguments.Free();
23302282
}
2283+
2284+
// check val escape of receiver if ref-like
2285+
if (receiverOpt?.Type?.IsRefLikeType == true)
2286+
{
2287+
// Should we also report ErrorCode.ERR_CallArgMixing if CheckValEscape() fails?
2288+
return CheckValEscape(receiverOpt.Syntax, receiverOpt, scopeOfTheContainingExpression, escapeTo, false, diagnostics);
2289+
}
2290+
2291+
return true;
23312292
}
23322293

23332294
private bool CheckInvocationArgMixingWithUpdatedRules(
@@ -2391,32 +2352,9 @@ private bool CheckInvocationArgMixingWithUpdatedRules(
23912352
}
23922353
}
23932354

2394-
inferDeclarationExpressionValEscape();
2395-
23962355
mixableArguments.Free();
23972356
escapeValues.Free();
23982357
return valid;
2399-
2400-
void inferDeclarationExpressionValEscape()
2401-
{
2402-
// find the widest scope that arguments could safely escape to.
2403-
// use this scope as the inferred STE of declaration expressions.
2404-
var inferredDestinationValEscape = CallingMethodScope;
2405-
foreach (var (_, fromArg, _, isRefEscape) in escapeValues)
2406-
{
2407-
inferredDestinationValEscape = Math.Max(inferredDestinationValEscape, isRefEscape
2408-
? GetRefEscape(fromArg, scopeOfTheContainingExpression)
2409-
: GetValEscape(fromArg, scopeOfTheContainingExpression));
2410-
}
2411-
2412-
foreach (var (_, fromArg, _, _) in escapeValues)
2413-
{
2414-
if (ShouldInferDeclarationExpressionValEscape(fromArg, out var localSymbol))
2415-
{
2416-
localSymbol.SetValEscape(inferredDestinationValEscape);
2417-
}
2418-
}
2419-
}
24202358
}
24212359

24222360
private static bool IsReceiverRefReadOnly(Symbol methodOrPropertySymbol) => methodOrPropertySymbol switch

src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,6 @@ internal virtual void SetRefEscape(uint value)
318318

319319
internal virtual void SetValEscape(uint value)
320320
{
321-
// either we should be setting the val escape for the first time,
322-
// or not contradicting what was set before.
323-
Debug.Assert(
324-
_valEscapeScope == Binder.CallingMethodScope
325-
|| _valEscapeScope == value);
326321
_valEscapeScope = value;
327322
}
328323

0 commit comments

Comments
 (0)