提交 5bcfa7cd 编写于 作者: V vsadov

The argument that stands for the receiver of a `ref` extension method must be...

The argument that stands for the receiver of a `ref` extension method must be always passed as `ref`
上级 a213194a
......@@ -964,22 +964,18 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
// (i.e. the first argument, if invokedAsExtensionMethod).
var gotError = MemberGroupFinalValidation(receiver, method, expression, diagnostics, invokedAsExtensionMethod);
ImmutableArray<BoundExpression> args;
if (invokedAsExtensionMethod)
{
BoundExpression receiverArgument;
BoundExpression receiverArgument = analyzedArguments.Argument(0);
ParameterSymbol receiverParameter = method.Parameters.First();
if ((object)receiver != methodGroup.Receiver)
// we will have a different receiver if ReplaceTypeOrValueReceiver has unwrapped TypeOrValue
if ((object)receiver != receiverArgument)
{
// Because the receiver didn't pass through CoerceArguments, we need to apply an appropriate conversion here.
Debug.Assert(argsToParams.IsDefault || argsToParams[0] == 0);
receiverArgument = CreateConversion(receiver, methodResult.Result.ConversionForArg(0), receiverParameter.Type, diagnostics);
}
else
{
receiverArgument = analyzedArguments.Argument(0);
}
if (receiverParameter.RefKind == RefKind.Ref)
{
......@@ -987,21 +983,24 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
// This helper method will also replace it with a BoundBadExpression if it was invalid.
receiverArgument = CheckValue(receiverArgument, BindValueKind.RefOrOut, diagnostics);
if (analyzedArguments.RefKinds.Count == 0)
{
analyzedArguments.RefKinds.Count = analyzedArguments.Arguments.Count;
}
// receiver of a `ref` extension method is a `ref` argument. (and we have checked above that it can be passed as a Ref)
// we need to adjust the argument refkind as if we had a `ref` modifier in a call.
analyzedArguments.RefKinds[0] = RefKind.Ref;
CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
else if (receiverParameter.RefKind == RefKind.In)
{
// NB: receiver of an `in` extension method is treated as a `byval` argument, so no changes from the default refkind is needed in that case.
Debug.Assert(analyzedArguments.RefKind(0) == RefKind.None);
CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
ArrayBuilder<BoundExpression> builder = ArrayBuilder<BoundExpression>.GetInstance(analyzedArguments.Arguments.Count);
builder.Add(receiverArgument);
builder.AddRange(analyzedArguments.Arguments.Skip(1));
args = builder.ToImmutableAndFree();
}
else
{
args = analyzedArguments.Arguments.ToImmutable();
analyzedArguments.Arguments[0] = receiverArgument;
}
// This will be the receiver of the BoundCall node that we create.
......@@ -1015,6 +1014,7 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
var argNames = analyzedArguments.GetNames();
var argRefKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
var args = analyzedArguments.Arguments.ToImmutable();
if (!gotError && !method.IsStatic && receiver != null && receiver.Kind == BoundKind.ThisReference && receiver.WasCompilerGenerated)
{
......
......@@ -305,5 +305,69 @@ static void Main()
}
}");
}
[WorkItem(24014, "https://github.com/dotnet/roslyn/issues/24014")]
[Fact]
public void RefExtensionMethods_OutParam()
{
var code = @"
using System;
public class C
{
public static void Main()
{
var inst = new S1();
int orig;
var result = inst.Mutate(out orig);
System.Console.Write(orig);
System.Console.Write(inst.x);
}
}
public static class S1_Ex
{
public static bool Mutate(ref this S1 instance, out int orig)
{
orig = instance.x;
instance.x = 42;
return true;
}
}
public struct S1
{
public int x;
}
";
var compilation = CreateCompilationWithMscorlibAndSystemCore(code, options: TestOptions.ReleaseExe);
var verifier = CompileAndVerify(compilation, expectedOutput: "042");
verifier.VerifyIL("C.Main", @"
{
// Code size 36 (0x24)
.maxstack 2
.locals init (S1 V_0, //inst
int V_1) //orig
IL_0000: ldloca.s V_0
IL_0002: initobj ""S1""
IL_0008: ldloca.s V_0
IL_000a: ldloca.s V_1
IL_000c: call ""bool S1_Ex.Mutate(ref S1, out int)""
IL_0011: pop
IL_0012: ldloc.1
IL_0013: call ""void System.Console.Write(int)""
IL_0018: ldloc.0
IL_0019: ldfld ""int S1.x""
IL_001e: call ""void System.Console.Write(int)""
IL_0023: ret
}");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册