Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #22381 - Use in for parameters and arguments #22424

Merged
merged 11 commits into from
Sep 29, 2017
64 changes: 32 additions & 32 deletions src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,8 @@ private bool CheckParameterValueKind(SyntaxNode node, BoundParameter parameter,
ParameterSymbol parameterSymbol = parameter.ParameterSymbol;

// all parameters can be passed by ref/out or assigned to
// except "ref readonly" parameters, which are readonly
if (parameterSymbol.RefKind == RefKind.RefReadOnly && RequiresAssignableVariable(valueKind))
// except "in" parameters, which are readonly
if (parameterSymbol.RefKind == RefKind.In && RequiresAssignableVariable(valueKind))
{
ReportReadOnlyError(parameterSymbol, node, valueKind, checkingReceiver, diagnostics);
return false;
Expand Down Expand Up @@ -961,7 +961,7 @@ bool isRefEscape
//by default it is safe to escape
uint escapeScope = Binder.ExternalScope;

ArrayBuilder<bool> refReadOnlyParametersMatchedWithArgs = null;
ArrayBuilder<bool> inParametersMatchedWithArgs = null;

if (!argsOpt.IsDefault)
{
Expand All @@ -985,7 +985,7 @@ bool isRefEscape
goto moreArguments;
}

RefKind effectiveRefKind = GetEffectiveRefKind(argIndex, argRefKindsOpt, parameters, argsToParamsOpt, ref refReadOnlyParametersMatchedWithArgs);
RefKind effectiveRefKind = GetEffectiveRefKind(argIndex, argRefKindsOpt, parameters, argsToParamsOpt, ref inParametersMatchedWithArgs);

// ref escape scope is the narrowest of
// - ref escape of all byref arguments
Expand All @@ -1003,20 +1003,20 @@ bool isRefEscape
if (escapeScope >= scopeOfTheContainingExpression)
{
// no longer needed
refReadOnlyParametersMatchedWithArgs?.Free();
inParametersMatchedWithArgs?.Free();

// can't get any worse
return escapeScope;
}
}
}

// handle omitted optional "ref readonly" parameters if there are any
ParameterSymbol unmatchedRefReadOnlyParameter = TryGetUnmatchedRefReadOnlyParameterAndFreeMatchedArgs(parameters, ref refReadOnlyParametersMatchedWithArgs);
// handle omitted optional "in" parameters if there are any
ParameterSymbol unmatchedInParameter = TryGetunmatchedInParameterAndFreeMatchedArgs(parameters, ref inParametersMatchedWithArgs);

// unmatched "ref readonly" parameter is the same as a literal, its ref escape is scopeOfTheContainingExpression (can't get any worse)
// unmatched "in" parameter is the same as a literal, its ref escape is scopeOfTheContainingExpression (can't get any worse)
// its val escape is ExternalScope (does not affect overal result)
if (unmatchedRefReadOnlyParameter != null && isRefEscape)
if (unmatchedInParameter != null && isRefEscape)
{
return scopeOfTheContainingExpression;
}
Expand Down Expand Up @@ -1065,7 +1065,7 @@ bool isRefEscape
receiverOpt = null;
}

ArrayBuilder<bool> refReadOnlyParametersMatchedWithArgs = null;
ArrayBuilder<bool> inParametersMatchedWithArgs = null;

if (!argsOpt.IsDefault)
{
Expand All @@ -1090,7 +1090,7 @@ bool isRefEscape
goto moreArguments;
}

RefKind effectiveRefKind = GetEffectiveRefKind(argIndex, argRefKindsOpt, parameters, argsToParamsOpt, ref refReadOnlyParametersMatchedWithArgs);
RefKind effectiveRefKind = GetEffectiveRefKind(argIndex, argRefKindsOpt, parameters, argsToParamsOpt, ref inParametersMatchedWithArgs);

// ref escape scope is the narrowest of
// - ref escape of all byref arguments
Expand All @@ -1105,7 +1105,7 @@ bool isRefEscape
if (!valid)
{
// no longer needed
refReadOnlyParametersMatchedWithArgs?.Free();
inParametersMatchedWithArgs?.Free();

ErrorCode errorCode = GetStandardCallEscapeError(checkingReceiver);

Expand All @@ -1126,14 +1126,14 @@ bool isRefEscape
}
}

// handle omitted optional "ref readonly" parameters if there are any
ParameterSymbol unmatchedRefReadOnlyParameter = TryGetUnmatchedRefReadOnlyParameterAndFreeMatchedArgs(parameters, ref refReadOnlyParametersMatchedWithArgs);
// handle omitted optional "in" parameters if there are any
ParameterSymbol unmatchedInParameter = TryGetunmatchedInParameterAndFreeMatchedArgs(parameters, ref inParametersMatchedWithArgs);

// unmatched "ref readonly" parameter is the same as a literal, its ref escape is scopeOfTheContainingExpression (can't get any worse)
// unmatched "in" parameter is the same as a literal, its ref escape is scopeOfTheContainingExpression (can't get any worse)
// its val escape is ExternalScope (does not affect overal result)
if (unmatchedRefReadOnlyParameter != null && isRefEscape)
if (unmatchedInParameter != null && isRefEscape)
{
Error(diagnostics, GetStandardCallEscapeError(checkingReceiver), syntax, symbol, unmatchedRefReadOnlyParameter.Name);
Error(diagnostics, GetStandardCallEscapeError(checkingReceiver), syntax, symbol, unmatchedInParameter.Name);
return false;
}

Expand Down Expand Up @@ -1263,7 +1263,7 @@ private static bool CheckInvocationArgMixing(
}
}

//NB: we do not care about unmatched "ref readonly" parameters here.
//NB: we do not care about unmatched "in" parameters here.
// They have "outer" val escape, so cannot be worse than escapeTo.

// check val escape of receiver if ref-like
Expand All @@ -1278,38 +1278,38 @@ private static bool CheckInvocationArgMixing(
/// <summary>
/// Gets "effective" ref kind of an argument.
/// Generally we know if a formal argument is passed as ref/out by looking at the call site.
/// However, to distinguish "ref readonly" and regular "val" parameters we need to take a look at corresponding parameter, if such exists.
/// NOTE: there are cases like params/vararg, when a corresponding parameter may not exist, then it cannot be a "ref readonly".
/// However, to distinguish "in" and regular "val" parameters we need to take a look at corresponding parameter, if such exists.
/// NOTE: there are cases like params/vararg, when a corresponding parameter may not exist, then it cannot be "in".
/// </summary>
private static RefKind GetEffectiveRefKind(
int argIndex,
ImmutableArray<RefKind> argRefKindsOpt,
ImmutableArray<ParameterSymbol> parameters,
ImmutableArray<int> argsToParamsOpt,
ref ArrayBuilder<bool> refReadOnlyParametersMatchedWithArgs)
ref ArrayBuilder<bool> inParametersMatchedWithArgs)
{
var effectiveRefKind = argRefKindsOpt.IsDefault ? RefKind.None : argRefKindsOpt[argIndex];
if (effectiveRefKind == RefKind.None && argIndex < parameters.Length)
{
var paramIndex = argsToParamsOpt.IsDefault ? argIndex : argsToParamsOpt[argIndex];

if (parameters[paramIndex].RefKind == RefKind.RefReadOnly)
if (parameters[paramIndex].RefKind == RefKind.In)
{
effectiveRefKind = RefKind.RefReadOnly;
refReadOnlyParametersMatchedWithArgs = refReadOnlyParametersMatchedWithArgs ?? ArrayBuilder<bool>.GetInstance(parameters.Length, fillWithValue: false);
refReadOnlyParametersMatchedWithArgs[paramIndex] = true;
effectiveRefKind = RefKind.In;
inParametersMatchedWithArgs = inParametersMatchedWithArgs ?? ArrayBuilder<bool>.GetInstance(parameters.Length, fillWithValue: false);
inParametersMatchedWithArgs[paramIndex] = true;
}
}

return effectiveRefKind;
}

/// <summary>
/// Gets a "ref readonly" parameter for which there is no argument supplied, if such exists.
/// That indicates an optional "ref readonly" parameter. We treat it as an RValue passed by reference via a temporary.
/// Gets a "in" parameter for which there is no argument supplied, if such exists.
/// That indicates an optional "in" parameter. We treat it as an RValue passed by reference via a temporary.
/// The effective scope of such variable is the immediately containing scope.
/// </summary>
private static ParameterSymbol TryGetUnmatchedRefReadOnlyParameterAndFreeMatchedArgs(ImmutableArray<ParameterSymbol> parameters, ref ArrayBuilder<bool> refReadOnlyParametersMatchedWithArgs)
private static ParameterSymbol TryGetunmatchedInParameterAndFreeMatchedArgs(ImmutableArray<ParameterSymbol> parameters, ref ArrayBuilder<bool> inParametersMatchedWithArgs)
{
try
{
Expand All @@ -1323,8 +1323,8 @@ private static ParameterSymbol TryGetUnmatchedRefReadOnlyParameterAndFreeMatched
break;
}

if (parameter.RefKind == RefKind.RefReadOnly &&
refReadOnlyParametersMatchedWithArgs?[i] != true &&
if (parameter.RefKind == RefKind.In &&
inParametersMatchedWithArgs?[i] != true &&
parameter.Type.IsByRefLikeType == false)
{
return parameter;
Expand All @@ -1336,9 +1336,9 @@ private static ParameterSymbol TryGetUnmatchedRefReadOnlyParameterAndFreeMatched
}
finally
{
refReadOnlyParametersMatchedWithArgs?.Free();
inParametersMatchedWithArgs?.Free();
// make sure noone uses it after.
refReadOnlyParametersMatchedWithArgs = null;
inParametersMatchedWithArgs = null;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@ private BoundCall BindInvocationExpressionContinued(

CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
else if (receiverParameter.RefKind == RefKind.RefReadOnly)
else if (receiverParameter.RefKind == RefKind.In)
{
CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
Expand Down
7 changes: 2 additions & 5 deletions src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,6 @@ private Tuple<ImmutableArray<RefKind>, ImmutableArray<TypeSymbol>, ImmutableArra
type = BindType(typeSyntax, diagnostics);
foreach (var modifier in p.Modifiers)
{
var modKind = modifier.Kind();

switch (modifier.Kind())
{
case SyntaxKind.RefKeyword:
Expand All @@ -139,9 +137,8 @@ private Tuple<ImmutableArray<RefKind>, ImmutableArray<TypeSymbol>, ImmutableArra
allValue = false;
break;

case SyntaxKind.ReadOnlyKeyword:
Debug.Assert(refKind == RefKind.Ref || syntax.HasErrors);
refKind = RefKind.RefReadOnly;
case SyntaxKind.InKeyword:
refKind = RefKind.In;
allValue = false;
break;

Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ internal void GenerateAnonymousFunctionConversionError(DiagnosticBag diagnostics

// Parameter {0} is declared as type '{1}{2}' but should be '{3}{4}'
Error(diagnostics, ErrorCode.ERR_BadParamType, lambdaParameterLocation,
i + 1, lambdaRefKind.ToPrefix(), distinguisher.First, delegateRefKind.ToPrefix(), distinguisher.Second);
i + 1, lambdaRefKind.ToParameterPrefix(), distinguisher.First, delegateRefKind.ToParameterPrefix(), distinguisher.Second);
}
else if (lambdaRefKind != delegateRefKind)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2575,9 +2575,9 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
{
var paramRefKind = parameter.RefKind;

if (paramRefKind == RefKind.RefReadOnly)
if (paramRefKind == RefKind.In)
{
// "ref readonly" parameters are effectively None for the purpose of overload resolution.
// "in" parameters are effectively None for the purpose of overload resolution.
paramRefKind = RefKind.None;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -950,17 +950,17 @@ private static void ReportBadArgumentError(
ParameterSymbol parameter = method.GetParameters()[parm];
bool isLastParameter = method.GetParameterCount() == parm + 1; // This is used to later decide if we need to try to unwrap a params array
RefKind refArg = arguments.RefKind(arg);
RefKind refParm = parameter.RefKind;
RefKind refParameter = parameter.RefKind;

if (arguments.IsExtensionMethodThisArgument(arg))
{
Debug.Assert(refArg == RefKind.None);
if (refParm == RefKind.Ref || refParm == RefKind.RefReadOnly)
if (refParameter == RefKind.Ref || refParameter == RefKind.In)
{
// For ref and ref-readonly extension methods, we omit the "ref" modifier on receiver arguments.
// Setting the correct RefKind for finding the correct diagnostics message.
// For other ref kinds, keeping it as it is to find mismatch errors.
refArg = refParm;
refArg = refParameter;
}
}

Expand All @@ -974,7 +974,7 @@ private static void ReportBadArgumentError(
{
// If the problem is that a lambda isn't convertible to the given type, also report why.
// The argument and parameter type might match, but may not have same in/out modifiers
if (argument.Kind == BoundKind.UnboundLambda && refArg == refParm)
if (argument.Kind == BoundKind.UnboundLambda && refArg == refParameter)
{
((UnboundLambda)argument).GenerateAnonymousFunctionConversionError(diagnostics, parameter.Type);
}
Expand All @@ -992,9 +992,9 @@ private static void ReportBadArgumentError(
UnwrapIfParamsArray(parameter, isLastParameter));
}
}
else if (refArg != refParm && !(refArg == RefKind.None && refParm == RefKind.RefReadOnly))
else if (refArg != refParameter && !(refArg == RefKind.None && refParameter == RefKind.In))
{
if (refParm == RefKind.None || refParm == RefKind.RefReadOnly)
if (refParameter == RefKind.None || refParameter == RefKind.In)
{
// Argument {0} should not be passed with the {1} keyword
diagnostics.Add(
Expand All @@ -1012,7 +1012,7 @@ private static void ReportBadArgumentError(
sourceLocation,
symbols,
arg + 1,
refParm.ToParameterDisplayString());
refParameter.ToParameterDisplayString());
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ private bool HasHome(BoundExpression expression, bool needWriteable)

case BoundKind.Parameter:
return !needWriteable ||
((BoundParameter)expression).ParameterSymbol.RefKind != RefKind.RefReadOnly;
((BoundParameter)expression).ParameterSymbol.RefKind != RefKind.In;

case BoundKind.Local:
// locals have home unless they are byval stack locals or ref-readonly
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ private void EmitArgument(BoundExpression argument, RefKind refKind)
EmitExpression(argument, true);
break;

case RefKind.RefReadOnly:
case RefKind.In:
var temp = EmitAddress(argument, AddressKind.ReadOnly);
AddExpressionTemp(temp);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ private BoundExpression Spill(

case BoundKind.Call:
var call = (BoundCall)expression;
if (refKind != RefKind.None && refKind != RefKind.RefReadOnly)
if (refKind != RefKind.None && refKind != RefKind.In)
{
Debug.Assert(call.Method.RefKind != RefKind.None);
_F.Diagnostics.Add(ErrorCode.ERR_RefReturningCallAndAwait, _F.Syntax.Location, call.Method);
Expand Down Expand Up @@ -794,7 +794,7 @@ public override BoundNode VisitCall(BoundCall node)

receiver = node.ReceiverOpt;
var refKind = node.Method.ContainingType.IsReadOnly?
RefKind.RefReadOnly:
RefKind.In:
ReceiverSpillRefKind(receiver);

receiver = Spill(receiverBuilder, VisitExpression(ref receiverBuilder, receiver), refKind: refKind);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ private void CheckRefReadOnlySymbols(MethodSymbol symbol)
{
foreach (var parameter in symbol.Parameters)
{
if (parameter.RefKind == RefKind.RefReadOnly)
if (parameter.RefKind == RefKind.In)
{
foundRefReadOnly = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,15 @@ private ImmutableArray<BoundExpression> MakeArguments(
}

/// <summary>
/// patch refKinds for "readonly ref" to have effective RefReadOnly kind.
/// Patch refKinds for "in" arguments to have effective RefKind.In
/// </summary>
private static ImmutableArray<RefKind> GetEffectiveArgumentRefKinds(ImmutableArray<RefKind> argumentRefKindsOpt, ImmutableArray<ParameterSymbol> parameters)
{
ArrayBuilder<RefKind> refKindsBuilder = null;
for (int i = 0; i < parameters.Length; i++)
{
var paramRefKind = parameters[i].RefKind;
if (paramRefKind == RefKind.RefReadOnly)
if (paramRefKind == RefKind.In)
{
if (refKindsBuilder == null)
{
Expand Down Expand Up @@ -661,9 +661,9 @@ private void BuildStoresToTemps(
BoundExpression argument = rewrittenArguments[a];
int p = (!argsToParamsOpt.IsDefault) ? argsToParamsOpt[a] : a;
RefKind refKind = argumentRefKinds.RefKinds(a);
if (refKind == RefKind.None && parameters[p].RefKind == RefKind.RefReadOnly)
if (refKind == RefKind.None && parameters[p].RefKind == RefKind.In)
{
refKind = RefKind.RefReadOnly;
refKind = RefKind.In;
}

Debug.Assert(arguments[p] == null);
Expand Down
Loading