|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Semantics
{
[CompilerTrait(CompilerFeature.RefLocalsReturns, CompilerFeature.RefLifetime)]
public class RefLocalsAndReturnsTests : CompilingTestBase
{
[Fact]
public void ReassignExpressionTree()
{
var comp = CreateCompilation(@"
using System;
using System.Linq.Expressions;
class C
{
void M()
{
int x = 0;
ref int rx = ref x;
Expression<Func<int>> e = () => (rx = ref x);
}
}");
comp.VerifyDiagnostics(
// (10,42): error CS8175: Cannot use ref local 'rx' inside an anonymous method, lambda expression, or query expression
// Expression<Func<int>> e = () => (rx = ref x);
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "rx").WithArguments("rx").WithLocation(10, 42));
}
[Fact]
public void RefEscapeInFor()
{
var comp = CreateCompilation(@"
class C
{
void M(ref int r1)
{
int x = 0;
ref int rx = ref x;
for (int i = 0; i < (r1 = ref rx); i++)
{
}
for (int i = 0; i < 5; (r1 = ref rx)++)
{
}
}
}");
comp.VerifyDiagnostics(
// (8,30): error CS8374: Cannot ref-assign 'rx' to 'r1' because 'rx' has a narrower escape scope than 'r1'.
// for (int i = 0; i < (r1 = ref rx); i++)
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r1 = ref rx").WithArguments("r1", "rx").WithLocation(8, 30),
// (11,33): error CS8374: Cannot ref-assign 'rx' to 'r1' because 'rx' has a narrower escape scope than 'r1'.
// for (int i = 0; i < 5; (r1 = ref rx)++)
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r1 = ref rx").WithArguments("r1", "rx").WithLocation(11, 33));
}
[Fact]
public void RefForMultipleDeclarations()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
for (ref int rx = ref x, ry = ref x;;)
{
rx += ry;
}
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void RefForNoInitializer()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int i = 0;
for (ref int rx; i < 5; i++) { }
}
}");
comp.VerifyDiagnostics(
// (7,22): error CS8174: A declaration of a by-reference variable must have an initializer
// for (ref int rx; i < 5; i++) { }
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "rx").WithLocation(7, 22),
// (7,22): warning CS0168: The variable 'rx' is declared but never used
// for (ref int rx; i < 5; i++) { }
Diagnostic(ErrorCode.WRN_UnreferencedVar, "rx").WithArguments("rx").WithLocation(7, 22));
}
[Fact]
public void RefReassignVolatileField()
{
var comp = CreateCompilation(@"
class C
{
volatile int _f;
void M()
{
ref int rx = ref _f;
rx = ref _f;
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void RefReassignDynamic()
{
var comp = CreateCompilation(@"
class C
{
void M(ref dynamic rd)
{
ref var rd2 = ref rd.Length; // Legal
rd = ref rd.Length; // Error, escape scope is local
}
}");
comp.VerifyDiagnostics(
// (7,9): error CS8374: Cannot ref-assign 'rd.Length' to 'rd' because 'rd.Length' has a narrower escape scope than 'rd'.
// rd = ref rd.Length; // Error, escape scope is local
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "rd = ref rd.Length").WithArguments("rd", "rd.Length").WithLocation(7, 9));
}
[Fact]
public void RefReassignIsUse()
{
var comp = CreateCompilation(@"
class C
{
private int _f = 0;
void M()
{
int x = 0, y = 0;
ref int rx = ref x;
rx = ref y;
rx = ref _f;
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void NoRefReassignThisInStruct()
{
var comp = CreateCompilation(@"
struct S
{
void M(ref S s)
{
s = ref this;
this = ref s;
}
}");
comp.VerifyDiagnostics(
// (6,9): error CS8374: Cannot ref-assign 'this' to 's' because 'this' has a narrower escape scope than 's'.
// s = ref this;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s = ref this").WithArguments("s", "this").WithLocation(6, 9),
// (7,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(7, 9));
}
[Fact]
public void RefReassignLifetimeIsLHS()
{
var comp = CreateCompilation(@"
class C
{
ref int M()
{
int x = 0;
ref int rx = ref x;
return ref (rx = ref (new int[1])[0]);
}
}");
comp.VerifyDiagnostics(
// (8,21): error CS8157: Cannot return 'rx' by reference because it was initialized to a value that cannot be returned by reference
// return ref (rx = ref (new int[1])[0]);
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "rx = ref (new int[1])[0]").WithArguments("rx").WithLocation(8, 21));
}
[Fact]
public void InReassignmentWithConversion()
{
var comp = CreateCompilation(@"
class C
{
void M(string s)
{
ref string rs = ref s;
M2(in (rs = ref s));
}
void M2(in object o) {}
}");
comp.VerifyDiagnostics(
// (7,16): error CS1503: Argument 1: cannot convert from 'in string' to 'in object'
// M2(in (rs = ref s));
Diagnostic(ErrorCode.ERR_BadArgType, "rs = ref s").WithArguments("1", "in string", "in object").WithLocation(7, 16));
}
[Fact]
public void RefEscapeInForeach()
{
var comp = CreateCompilationWithMscorlibAndSpan(@"
using System;
class C
{
ref int M(Span<int> s)
{
foreach (ref int x in s)
{
if (x == 0)
{
return ref x; // OK
}
}
Span<int> s2 = stackalloc int[10];
foreach (ref int x in s2)
{
if (x == 0)
{
return ref x; // error
}
}
return ref s[0];
}
}");
comp.VerifyDiagnostics(
// (20,28): error CS8157: Cannot return 'x' by reference because it was initialized to a value that cannot be returned by reference
// return ref x; // error
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "x").WithArguments("x").WithLocation(20, 28));
}
[Fact]
public void RefFor72()
{
var comp = CreateCompilation(@"
class C
{
void M(int x)
{
for (ref int rx = ref x; x < 0; x++) { }
}
}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_2));
comp.VerifyDiagnostics(
// (6,14): error CS8320: Feature 'ref for-loop variables' is not available in C# 7.2. Please use language version 7.3 or greater.
// for (ref int rx = ref x; x < 0; x++) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref int").WithArguments("ref for-loop variables", "7.3").WithLocation(6, 14));
}
[Fact]
public void RefForEach72()
{
var comp = CreateCompilationWithMscorlibAndSpan(@"
using System;
class C
{
void M(Span<int> span)
{
foreach (ref int x in span) { }
}
}", parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_2));
comp.VerifyDiagnostics(
// (7,18): error CS8320: Feature 'ref foreach iteration variables' is not available in C# 7.2. Please use language version 7.3 or greater.
// foreach (ref int x in span) { }
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref int").WithArguments("ref foreach iteration variables", "7.3").WithLocation(7, 18));
}
[Fact]
public void RefReturnRefExpression()
{
var comp = CreateCompilation(@"
class C
{
readonly int _ro = 42;
int _rw = 42;
ref int M1(ref int rrw) => ref (rrw = ref _rw);
ref readonly int M2(in int rro) => ref (rro = ref _ro);
ref readonly int M3(in int rro) => ref (rro = ref _rw);
ref int M4(in int rro) => ref (rro = ref _rw);
ref int M5(ref int rrw) => ref (rrw = ref _ro);
}");
comp.VerifyDiagnostics(
// (13,36): error CS8333: Cannot return variable 'rro' by writable reference because it is a readonly variable
// ref int M4(in int rro) => ref (rro = ref _rw);
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "rro = ref _rw").WithArguments("variable", "rro").WithLocation(13, 36),
// (15,47): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
// ref int M5(ref int rrw) => ref (rrw = ref _ro);
Diagnostic(ErrorCode.ERR_AssgReadonly, "_ro").WithLocation(15, 47));
}
[Fact, WorkItem(42259, "https://github.com/dotnet/roslyn/issues/42259")]
public void RefReturnLocalFunction()
{
var source = @"
#pragma warning disable CS8321
class C {
static void M(){
ref int M1(in int i) => ref i;
ref int M2(in int i) { return ref i; }
ref readonly int M3(in int i) => ref i;
ref readonly int M4(in int i) { return ref i; }
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (5,37): error CS8333: Cannot return variable 'i' by writable reference because it is a readonly variable
// ref int M1(in int i) => ref i;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(5, 37),
// (6,43): error CS8333: Cannot return variable 'i' by writable reference because it is a readonly variable
// ref int M2(in int i) { return ref i; }
Diagnostic(ErrorCode.ERR_RefReturnReadonlyNotField, "i").WithArguments("variable", "i").WithLocation(6, 43)
);
}
[Fact, WorkItem(42259, "https://github.com/dotnet/roslyn/issues/42259")]
public void RefReadonlyReturnLocalFunction()
{
var source = @"
#pragma warning disable CS8321
class C {
ref int M(){
throw new System.Exception();
ref readonly int M1(in int i) => ref i;
ref readonly int M2(in int i) { return ref i; }
}
}";
CreateCompilation(source).VerifyDiagnostics();
}
[Fact]
public void ReadonlyFieldRefReassign()
{
var comp = CreateCompilation(@"
class C
{
readonly int _ro = 42;
int _rw = 42;
void M()
{
ref readonly var rro = ref _ro;
ref var rrw = ref _rw;
rrw = ref (rro = ref _ro);
rrw = ref (rro = ref rrw);
rrw = ref (true
? ref (rro = ref _rw)
: ref (rrw = ref _rw));
}
}");
comp.VerifyDiagnostics(
// (12,20): error CS1510: A ref or out value must be an assignable variable
// rrw = ref (rro = ref _ro);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "rro = ref _ro").WithLocation(12, 20),
// (13,20): error CS1510: A ref or out value must be an assignable variable
// rrw = ref (rro = ref rrw);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "rro = ref rrw").WithLocation(13, 20),
// (16,28): error CS1510: A ref or out value must be an assignable variable
// ? ref (rro = ref _rw)
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "rro = ref _rw").WithLocation(16, 28),
// (15,20): error CS1510: A ref or out value must be an assignable variable
// rrw = ref (true
Diagnostic(ErrorCode.ERR_RefLvalueExpected, @"true
? ref (rro = ref _rw)
: ref (rrw = ref _rw)").WithLocation(15, 20));
}
[Fact]
public void RefForeachErrorRecovery()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
foreach (ref var x in )
{
}
}
}");
comp.VerifyDiagnostics(
// (6,31): error CS1525: Invalid expression term ')'
// foreach (ref var x in )
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 31));
}
[Fact]
public void RefForToReadonly()
{
var comp = CreateCompilation(@"
class C
{
void M(in int x)
{
for (ref int i = ref x; i < 0; i++) {}
}
}");
comp.VerifyDiagnostics(
// (6,30): error CS8329: Cannot use variable 'x' as a ref or out value because it is a readonly variable
// for (ref int i = ref x; i < 0; i++) {}
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "x").WithArguments("variable", "x").WithLocation(6, 30));
}
[Fact]
public void RefForOutOfScope()
{
var comp = CreateCompilation(@"
class C
{
ref int M()
{
int x = 0;
for (ref int i = ref x; i < 0; i++)
{
if (i == 0)
{
return ref i;
}
}
return ref (new int[1])[0];
}
}");
comp.VerifyDiagnostics(
// (11,28): error CS8157: Cannot return 'i' by reference because it was initialized to a value that cannot be returned by reference
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i").WithArguments("i").WithLocation(11, 28));
}
[Fact]
public void RefForeachReadonly()
{
var comp = CreateCompilation(@"
using System;
class C
{
void M()
{
foreach (ref var v in new int[0])
{
}
foreach (ref readonly var v in new int[0])
{
}
foreach (ref var v in new RefEnumerable())
{
Console.WriteLine(v);
}
}
}
class RefEnumerable
{
private readonly int[] _arr = new int[5];
public StructEnum GetEnumerator() => new StructEnum(_arr);
public struct StructEnum
{
private readonly int[] _arr;
private int _current;
public StructEnum(int[] arr)
{
_arr = arr;
_current = -1;
}
public ref readonly int Current => ref _arr[_current];
public bool MoveNext() => ++_current != _arr.Length;
}
}");
comp.VerifyDiagnostics(
// (7,31): error CS1510: A ref or out value must be an assignable variable
// foreach (ref var v in new int[0])
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new int[0]").WithLocation(7, 31),
// (10,40): error CS1510: A ref or out value must be an assignable variable
// foreach (ref readonly var v in new int[0])
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new int[0]").WithLocation(10, 40),
// (13,31): error CS8331: Cannot assign to method 'Current.get' or use it as the right hand side of a ref assignment because it is a readonly variable
// foreach (ref var v in new RefEnumerable())
Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "new RefEnumerable()").WithArguments("method", "Current.get").WithLocation(13, 31));
}
[Fact]
public void RefReassignIdentityConversion()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
string s = ""s"";
object o = s;
ref string rs = ref s;
ref object ro = ref o;
rs = ref (string)o;
ro = ref s;
ro = s;
}
}");
comp.VerifyDiagnostics(
// (11,18): error CS1510: A ref or out value must be an assignable variable
// rs = ref (string)o;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "(string)o").WithLocation(11, 18),
// (12,18): error CS8173: The expression must be of type 'object' because it is being assigned by reference
// ro = ref s;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "s").WithArguments("object").WithLocation(12, 18));
}
[Fact]
public void RefReassign71()
{
var tree = SyntaxFactory.ParseSyntaxTree(@"
class C
{
static int _f = 0;
void M(ref int x, out int o)
{
x = ref _f;
ref int z = ref x;
z = ref _f;
o = 0;
o = ref _f;
}
}", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_2));
CreateCompilation(tree).VerifyDiagnostics(
// (7,13): error CS8320: Feature 'ref reassignment' is not available in C# 7.2. Please use language version 7.3 or greater.
// x = ref _f;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref").WithArguments("ref reassignment", "7.3").WithLocation(7, 13),
// (10,13): error CS8320: Feature 'ref reassignment' is not available in C# 7.2. Please use language version 7.3 or greater.
// z = ref _f;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref").WithArguments("ref reassignment", "7.3").WithLocation(10, 13),
// (12,13): error CS8320: Feature 'ref reassignment' is not available in C# 7.2. Please use language version 7.3 or greater.
// o = ref _f;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "ref").WithArguments("ref reassignment", "7.3").WithLocation(12, 13));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
public void RefReassignSpanLifetime(LanguageVersion languageVersion)
{
string source = @"using System;
class C
{
void M(ref Span<int> s)
{
Span<int> s2 = new Span<int>(new int[10]);
s = ref s2; // Illegal, narrower escape scope
s2 = stackalloc int[10]; // Illegal, narrower lifetime
Span<int> s3 = stackalloc int[10];
s = ref s3; // Illegal, narrower escape scope
}
}";
var comp = CreateCompilationWithMscorlibAndSpan(new[] { source, UnscopedRefAttributeDefinition }, parseOptions: TestOptions.Regular.WithLanguageVersion(languageVersion));
comp.VerifyDiagnostics(
// (8,9): error CS8374: Cannot ref-assign 's2' to 's' because 's2' has a narrower escape scope than 's'.
// s = ref s2; // Illegal, narrower escape scope
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s = ref s2").WithArguments("s", "s2").WithLocation(8, 9),
// (10,14): error CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method
// s2 = stackalloc int[10]; // Illegal, narrower lifetime
Diagnostic(ErrorCode.ERR_EscapeStackAlloc, "stackalloc int[10]").WithArguments("System.Span<int>").WithLocation(10, 14),
// (13,9): error CS8374: Cannot ref-assign 's3' to 's' because 's3' has a narrower escape scope than 's'.
// s = ref s3; // Illegal, narrower escape scope
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s = ref s3").WithArguments("s", "s3").WithLocation(13, 9));
}
[Fact]
public void RefReassignReferenceLocalToParam()
{
var comp = CreateCompilation(@"
class C
{
void M(ref string s)
{
var s2 = string.Empty;
s = ref s2;
}
}");
comp.VerifyDiagnostics(
// (7,9): error CS8356: Cannot ref-assign 's2' to 's' because 's2' has a narrower escape scope than 's'.
// s = ref s2;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "s = ref s2").WithArguments("s", "s2").WithLocation(7, 9));
}
[Fact]
public void RefAssignReferencePropertyToParam()
{
var comp = CreateCompilation(@"
class C
{
string s2 => string.Empty;
void M(ref string s)
{
s = ref s2;
}
}");
comp.VerifyDiagnostics(
// (8,17): error CS1510: A ref or out value must be an assignable variable
// s = ref s2;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "s2").WithLocation(8, 17));
}
[Fact]
public void RefAssignReferenceFileToParam()
{
var comp = CreateCompilation(@"
class C
{
string _s2 = string.Empty;
void M(ref string s)
{
s = ref _s2;
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void RefAssignStaticField()
{
var comp = CreateCompilation(@"
class C
{
void M(ref string s)
{
s = ref string.Empty;
}
}");
comp.VerifyDiagnostics(
// (6,17): error CS0198: A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)
// s = ref string.Empty;
Diagnostic(ErrorCode.ERR_AssgReadonlyStatic, "string.Empty").WithLocation(6, 17));
}
[Fact]
public void RefReassignForEach()
{
var comp = CreateCompilation(@"
using System;
class E
{
public class Enumerator
{
public ref int Current => throw new NotImplementedException();
public bool MoveNext() => throw new NotImplementedException();
}
public Enumerator GetEnumerator() => new Enumerator();
}
class C
{
void M()
{
foreach (ref int x in new E())
{
int y = 0;
x = ref y;
}
}
}");
comp.VerifyDiagnostics(
// (21,13): error CS1656: Cannot assign to 'x' because it is a 'foreach iteration variable'
// x = ref y;
Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "x").WithArguments("x", "foreach iteration variable").WithLocation(21, 13));
}
[Fact]
public void RefReassignNarrowLifetime()
{
var comp = CreateCompilation(@"
class C
{
int _x = 0;
void M()
{
int y = 0;
ref int rx = ref _x;
rx = ref y;
}
}");
comp.VerifyDiagnostics(
// (9,9): error CS8356: Cannot ref-assign 'y' to 'rx' because 'y' has a narrower escape scope than 'rx'.
// rx = ref y;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "rx = ref y").WithArguments("rx", "y").WithLocation(9, 9));
}
[Fact]
public void RefReassignRangeVar()
{
var comp = CreateCompilation(@"
using System;
using System.Linq;
class C
{
void M()
{
_ = from c in ""test"" select (Action)(() =>
{
int x = 0;
ref int rx = ref x;
rx = ref c;
c = ref x;
});
}
}");
comp.VerifyDiagnostics(
// (12,22): error CS1939: Cannot pass the range variable 'c' as an out or ref parameter
// rx = ref c;
Diagnostic(ErrorCode.ERR_QueryOutRefRangeVariable, "c").WithArguments("c").WithLocation(12, 22),
// (13,13): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// c = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c").WithLocation(13, 13));
}
[Fact]
public void RefReassignOutDefiniteAssignment()
{
var comp = CreateCompilation(@"
class C
{
static int y = 0;
void M(out int x)
{
x = ref y;
x = 0;
}
}");
comp.VerifyDiagnostics(
// (7,9): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method
// x = ref y;
Diagnostic(ErrorCode.ERR_ParamUnassigned, "x").WithArguments("x").WithLocation(7, 9));
}
[Fact]
public void RefReassignOutDefiniteAssignment2()
{
var source = @"
class C
{
void M(out int x)
{
x = 0;
int y;
x = ref y;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10);
comp.VerifyDiagnostics(
// (8,9): error CS8356: Cannot ref-assign 'y' to 'x' because 'y' has a narrower escape scope than 'x'.
// x = ref y;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x = ref y").WithArguments("x", "y").WithLocation(8, 9),
// (8,17): error CS0165: Use of unassigned local variable 'y'
// x = ref y;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(8, 17));
comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,17): error CS0165: Use of unassigned local variable 'y'
// x = ref y;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(8, 17));
}
[Fact]
public void RefReassignParamEscape()
{
var comp = CreateCompilation(@"
class C
{
void M(ref int x)
{
int y = 0;
x = ref y;
ref int z = ref y;
x = ref z;
}
}");
comp.VerifyDiagnostics(
// (7,9): error CS8356: Cannot ref-assign 'y' to 'x' because 'y' has a narrower escape scope than 'x'.
// x = ref y;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x = ref y").WithArguments("x", "y").WithLocation(7, 9),
// (10,9): error CS8356: Cannot ref-assign 'z' to 'x' because 'z' has a narrower escape scope than 'x'.
// x = ref z;
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "x = ref z").WithArguments("x", "z").WithLocation(10, 9));
}
[Fact]
public void RefReassignParamEscape_UnsafeContext()
{
var comp = CreateCompilation(@"
class C
{
unsafe void M(ref int x)
{
int y = 0;
x = ref y;
ref int z = ref y;
x = ref z;
}
}", options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (7,9): warning CS9085: This ref-assigns 'y' to 'x' but 'y' has a narrower escape scope than 'x'.
// x = ref y;
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "x = ref y").WithArguments("x", "y").WithLocation(7, 9),
// (10,9): warning CS9085: This ref-assigns 'z' to 'x' but 'z' has a narrower escape scope than 'x'.
// x = ref z;
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "x = ref z").WithArguments("x", "z").WithLocation(10, 9)
);
}
[Fact]
public void RefReassignThisStruct()
{
var comp = CreateCompilation(@"
struct S
{
int _f;
public S(int x) { _f = x; }
void M()
{
var s = new S(0);
this = ref s;
ref var s2 = ref s;
this = ref s2;
ref readonly var s3 = ref s;
this = ref s3;
this = ref (new S[1])[0];
ref var s4 = ref (new S[1])[0];
this = ref s4;
ref readonly var s5 = ref (new S[1])[0];
this = ref s5;
}
}");
comp.VerifyDiagnostics(
// (10,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(10, 9),
// (13,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s2;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(13, 9),
// (16,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s3;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(16, 9),
// (18,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref (new S[1])[0];
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(18, 9),
// (21,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s4;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(21, 9),
// (24,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref s5;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(24, 9));
}
[Fact]
public void RefReassignThisClass()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
this = ref (new int[1])[0];
}
}");
comp.VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// this = ref (new int[1])[0];
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9));
}
[Fact]
public void RefReassignField()
{
var comp = CreateCompilation(@"
class C
{
int _f = 0;
void M()
{
_f = ref (new int[1])[0];
}
}");
comp.VerifyDiagnostics(
// (7,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// _f = ref (new int[1])[0];
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "_f").WithLocation(7, 9));
}
[Fact]
public void RefReassignOperatorResult()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
(2 + 3) = ref x;
}
}");
comp.VerifyDiagnostics(
// (7,10): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// (2 + 3) = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "2 + 3").WithLocation(7, 10));
}
[Fact]
public void RefReassignToValue()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
int y = 0;
x = ref y;
}
}");
comp.VerifyDiagnostics(
// (8,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// x = ref y;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x").WithLocation(8, 9));
}
[Fact]
public void RefReassignWithReadonly()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
ref int rx = ref x;
ref readonly int rrx = ref x;
rx = ref rrx;
}
}");
comp.VerifyDiagnostics(
// (9,18): error CS1510: A ref or out value must be an assignable variable
// rx = ref rrx;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "rrx").WithLocation(9, 18));
}
[Fact]
public void RefReassignToRefReturn()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
ref int rx = ref M2();
M2() = ref x;
}
ref int M2() => ref (new int[1])[0];
}");
comp.VerifyDiagnostics(
// (8,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// M2() = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "M2()").WithLocation(8, 9));
}
[Fact]
public void RefReassignToProperty()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
ref int rx = ref P;
P = ref x;
}
ref int P
{
get => ref (new int[1])[0];
}
}");
comp.VerifyDiagnostics(
// (8,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// P = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "P").WithLocation(8, 9));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")]
public void RefReassignToRefTernary()
{
var source = """
class C
{
void M(bool b, ref int x, ref int y, ref int z)
{
(b ? ref x : ref y) = ref z;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// (b ? ref x : ref y) = ref z;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "b ? ref x : ref y").WithLocation(5, 10));
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/75023")]
public void RefReassignToRefAssignment()
{
var source = """
class C
{
void M(ref int x, ref int y, ref int z)
{
(x = ref y) = ref z;
}
}
""";
CreateCompilation(source).VerifyDiagnostics(
// (5,10): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// (x = ref y) = ref z;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x = ref y").WithLocation(5, 10));
}
[Fact, WorkItem(44153, "https://github.com/dotnet/roslyn/issues/44153")]
public void RefErrorProperty()
{
CreateCompilation(@"
public class C {
public ref ERROR Prop => throw null!;
}
").VerifyEmitDiagnostics(
// (3,16): error CS0246: The type or namespace name 'ERROR' could not be found (are you missing a using directive or an assembly reference?)
// public ref ERROR Prop => throw null!;
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "ERROR").WithArguments("ERROR").WithLocation(3, 16));
}
[Fact]
public void RefReadonlyOnlyIn72()
{
var tree = SyntaxFactory.ParseSyntaxTree(@"
class C
{
void M()
{
int x = 0;
ref readonly int y = ref x;
}
}", options: TestOptions.Regular7_1);
var comp = CreateCompilation(tree);
comp.VerifyDiagnostics(
// (7,13): error CS8302: Feature 'readonly references' is not available in C# 7.1. Please use language version 7.2 or greater.
// ref readonly int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_1, "readonly").WithArguments("readonly references", "7.2").WithLocation(7, 13));
}
[Fact]
public void CovariantConversionRefReadonly()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
string s = string.Empty;
ref readonly object x = ref s;
}
}");
comp.VerifyDiagnostics(
// (7,37): error CS8173: The expression must be of type 'object' because it is being assigned by reference
// ref readonly object x = ref s;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "s").WithArguments("object").WithLocation(7, 37));
}
[Fact]
public void ImplicitNumericRefReadonlyConversion()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
int x = 0;
ref readonly long y = ref x;
}
}");
comp.VerifyDiagnostics(
// (7,35): error CS8173: The expression must be of type 'long' because it is being assigned by reference
// ref readonly long y = ref x;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "x").WithArguments("long").WithLocation(7, 35));
}
[Fact]
public void RefReadonlyLocalToLiteral()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
ref readonly int x = ref 42;
}
}");
comp.VerifyDiagnostics(
// (6,34): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// ref readonly int x = ref 42;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "42").WithLocation(6, 34));
}
[Fact]
public void RefReadonlyNoCaptureInLambda()
{
var comp = CreateCompilation(@"
using System;
class C
{
void M()
{
ref readonly int x = ref (new int[1])[0];
Action a = () =>
{
int i = x;
};
}
}");
comp.VerifyDiagnostics(
// (10,21): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression
// int i = x;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(10, 21));
}
[Fact]
public void RefReadonlyInLambda()
{
var comp = CreateCompilation(@"
using System;
class C
{
void M()
{
Action a = () =>
{
ref readonly int x = ref (new int[1])[0];
int i = x;
};
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void RefReadonlyNoCaptureInLocalFunction()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
ref readonly int x = ref (new int[1])[0];
void Local()
{
int i = x;
}
Local();
}
}");
comp.VerifyDiagnostics(
// (9,21): error CS8175: Cannot use ref local 'x' inside an anonymous method, lambda expression, or query expression
// int i = x;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "x").WithArguments("x").WithLocation(9, 21));
}
[Fact]
public void RefReadonlyInLocalFunction()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
void Local()
{
ref readonly int x = ref (new int[1])[0];
int i = x;
}
Local();
}
}");
comp.VerifyDiagnostics();
}
[Fact]
public void RefReadonlyInAsync()
{
var comp = CreateCompilationWithMscorlib46(@"
using System.Threading.Tasks;
class C
{
async Task M()
{
ref readonly int x = ref (new int[1])[0];
int i = x;
await Task.FromResult(false);
}
}");
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefReadonlyInIterator()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
ref readonly int x = ref (new int[1])[0];
int i = x;
yield return i;
}
}");
comp.VerifyEmitDiagnostics();
}
[Fact]
public void RefReadonlyInIterator_ForEach()
{
var source = """
using System.Collections.Generic;
class C
{
int[] arr = new int[2];
IEnumerable<int> M()
{
ref readonly int[] x = ref arr;
foreach (var i in x)
{
System.Console.Write(i);
yield return 1;
}
foreach (var j in x)
{
System.Console.Write(j);
yield return 2;
}
}
}
""";
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (7,28): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref readonly int[] x = ref arr;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "x").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 28));
var expectedDiagnostics = new[]
{
// (15,27): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
// foreach (var j in x)
Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "x").WithLocation(15, 27)
};
CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void RefReadonlyInIterator_ForEach_02()
{
var source = """
using System.Collections.Generic;
foreach (var i in new C().M()) System.Console.Write(i);
class C
{
int[] arr = new[] { 4, 5 };
public IEnumerable<int> M()
{
ref readonly int[] x = ref arr;
foreach (var i in x)
{
System.Console.Write(i);
yield return 1;
}
}
}
""";
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (10,28): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref readonly int[] x = ref arr;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "x").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 28));
var expectedOutput = "4151";
CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: expectedOutput).VerifyDiagnostics();
CompileAndVerify(source, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_01()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
ref readonly int x = ref (new int[1])[0];
yield return 1;
yield return x;
local();
void local()
{
ref readonly int z = ref (new int[1])[0];
}
break;
}
}
}");
comp.VerifyEmitDiagnostics(
// (12,30): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
// yield return x;
Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "x").WithLocation(12, 30));
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_02()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
ref readonly int x; // 1
yield return 1;
yield return x; // 2
break;
}
}
}");
comp.VerifyDiagnostics(
// (10,34): error CS8174: A declaration of a by-reference variable must have an initializer
// ref readonly int x; // 1
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "x").WithLocation(10, 34),
// (12,30): error CS0165: Use of unassigned local variable 'x'
// yield return x; // 2
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(12, 30));
}
[Fact]
public void RefReadonlyInSwitchCaseInIterator_03()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
switch (this)
{
default:
foreach (ref readonly int x in (new int[1]))
yield return 1;
break;
}
}
}");
comp.VerifyDiagnostics(
// (10,49): error CS1510: A ref or out value must be an assignable variable
// foreach (ref readonly int x in (new int[1]))
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new int[1]").WithLocation(10, 49));
}
[Fact]
public void RefReadonlyInEmbeddedStatementInIterator()
{
var comp = CreateCompilation(@"
using System.Collections.Generic;
class C
{
IEnumerable<int> M()
{
if (true)
ref int x = ref (new int[1])[0]; // 1
yield return 1;
}
}");
comp.VerifyDiagnostics(
// (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
// ref int x = ref (new int[1])[0]; // 1
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13));
}
[Fact]
public void RefReadonlyInEmbeddedStatementInAsync()
{
var comp = CreateCompilation(@"
using System.Threading.Tasks;
class C
{
async Task M()
{
if (true)
ref int x = ref (new int[1])[0]; // 1
await Task.Yield();
}
}");
comp.VerifyDiagnostics(
// (8,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
// ref int x = ref (new int[1])[0]; // 1
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "ref int x = ref (new int[1])[0];").WithLocation(8, 13));
}
[Fact]
public void RefReadonlyLocalNotWritable()
{
var comp = CreateCompilation(@"
struct S
{
public int X;
public S(int x) => X = x;
public void AddOne() => this.X++;
}
class C
{
void M()
{
S s = new S(0);
ref readonly S rs = ref s;
s.X++;
rs.X++;
s.AddOne();
rs.AddOne();
s.X = 0;
rs.X = 0;
}
}");
comp.VerifyDiagnostics(
// (17,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer
// rs.X++;
Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "rs.X").WithLocation(17, 9),
// (21,9): error CS0131: The left-hand side of an assignment must be a variable, property or indexer
// rs.X = 0;
Diagnostic(ErrorCode.ERR_AssgLvalueExpected, "rs.X").WithLocation(21, 9));
}
[Fact]
public void StripReadonlyInReturn()
{
var comp = CreateCompilation(@"
class C
{
ref int M(ref int p)
{
ref readonly int rp = ref p;
return ref rp;
}
}");
comp.VerifyDiagnostics(
// (7,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref rp;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "rp").WithLocation(7, 20));
}
[Fact]
public void MixingRefParams()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
void L(ref int x, in int y)
{
L(ref x, y);
L(ref y, x);
L(ref x, ref x);
ref readonly int xr = ref x;
L(ref x, xr);
L(ref x, ref xr);
L(ref xr, y);
}
}
}");
comp.VerifyDiagnostics(
// (9,19): error CS8329: Cannot use variable 'y' as a ref or out value because it is a readonly variable
// L(ref y, x);
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "y").WithArguments("variable", "y").WithLocation(9, 19),
// (10,26): warning CS9191: The 'ref' modifier for argument 2 corresponding to 'in' parameter is equivalent to 'in'. Consider using 'in' instead.
// L(ref x, ref x);
Diagnostic(ErrorCode.WRN_BadArgRef, "x").WithArguments("2").WithLocation(10, 26),
// (14,26): error CS1510: A ref or out value must be an assignable variable
// L(ref x, ref xr);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "xr").WithLocation(14, 26),
// (15,19): error CS1510: A ref or out value must be an assignable variable
// L(ref xr, y);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "xr").WithLocation(15, 19));
}
[Fact]
public void AssignRefReadonlyToRefParam()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
void L(ref int p) { }
L(ref 42);
int x = 0;
ref readonly int xr = ref x;
L(xr);
L(ref xr);
ref readonly int L2() => ref (new int[1])[0];
L(L2());
L(ref L2());
}
}");
comp.VerifyDiagnostics(
// (8,15): error CS1510: A ref or out value must be an assignable variable
// L(ref 42);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "42").WithLocation(8, 15),
// (11,11): error CS1620: Argument 1 must be passed with the 'ref' keyword
// L(xr);
Diagnostic(ErrorCode.ERR_BadArgRef, "xr").WithArguments("1", "ref").WithLocation(11, 11),
// (12,15): error CS1510: A ref or out value must be an assignable variable
// L(ref xr);
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "xr").WithLocation(12, 15),
// (16,11): error CS1620: Argument 1 must be passed with the 'ref' keyword
// L(L2());
Diagnostic(ErrorCode.ERR_BadArgRef, "L2()").WithArguments("1", "ref").WithLocation(16, 11),
// (17,15): error CS8329: Cannot use method 'L2' as a ref or out value because it is a readonly variable
// L(ref L2());
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "L2()").WithArguments("method", "L2").WithLocation(17, 15));
}
[Fact]
public void AssignRefReadonlyLocalToRefLocal()
{
var comp = CreateCompilation(@"
class C
{
void M()
{
ref readonly int L() => ref (new int[1])[0];
ref int w = ref L();
ref readonly int x = ref L();
ref int y = x;
ref int z = ref x;
}
}");
comp.VerifyDiagnostics(
// (8,25): error CS8329: Cannot use method 'L' as a ref or out value because it is a readonly variable
// ref int w = ref L();
Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "L()").WithArguments("method", "L").WithLocation(8, 25),
// (10,17): error CS8172: Cannot initialize a by-reference variable with a value
// ref int y = x;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "y = x").WithLocation(10, 17),
// (10,21): error CS1510: A ref or out value must be an assignable variable
// ref int y = x;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "x").WithLocation(10, 21),
// (11,25): error CS1510: A ref or out value must be an assignable variable
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "x").WithLocation(11, 25)
);
}
[Fact]
public void RefLocalMissingInitializer()
{
var text = @"
class Test
{
void A()
{
ref int x;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (6,17): error CS8174: A declaration of a by-reference variable must have an initializer
// ref int x;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "x").WithLocation(6, 17),
// (6,17): warning CS0168: The variable 'x' is declared but never used
// ref int x;
Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(6, 17)
);
}
[Fact]
public void RefLocalHasValueInitializer()
{
var text = @"
class Test
{
void A()
{
int a = 123;
ref int x = a;
var y = x;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (7,17): error CS8172: Cannot initialize a by-reference variable with a value
// ref int x = a;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "x = a").WithLocation(7, 17)
);
}
[Fact]
public void ValLocalHasRefInitializer()
{
var text = @"
class Test
{
void A()
{
int a = 123;
ref int x = ref a;
var y = ref x;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (8,13): error CS8171: Cannot initialize a by-value variable with a reference
// var y = ref x;
Diagnostic(ErrorCode.ERR_InitializeByValueVariableWithReference, "y = ref x").WithLocation(8, 13)
);
}
[Fact]
public void RefReturnNotLValue()
{
var text = @"
class Test
{
ref int A()
{
return ref 2 + 2;
}
ref int B()
{
return ref 2;
}
ref object C()
{
return ref null;
}
void VoidMethod(){}
ref object D()
{
return ref VoidMethod();
}
int P1 {get{return 1;} set{}}
ref int E()
{
return ref P1;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (6,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref 2 + 2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2 + 2").WithLocation(6, 20),
// (11,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref 2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(11, 20),
// (16,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref null;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "null").WithLocation(16, 20),
// (23,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref VoidMethod();
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(23, 20),
// (30,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// return ref P1;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithLocation(30, 20)
);
}
[Fact]
public void RefReturnNotLValue1()
{
var text = @"
class Test
{
delegate ref int D1();
delegate ref object D2();
void Test1()
{
D1 d1 = () => ref 2 + 2;
D1 d2 = () => ref 2;
D2 d3 = () => ref null;
D2 d4 = () => ref VoidMethod();
D1 d5 = () => ref P1;
}
void VoidMethod(){}
int P1 {get{return 1;} set{}}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (9,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// D1 d1 = () => ref 2 + 2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2 + 2").WithLocation(9, 27),
// (10,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// D1 d2 = () => ref 2;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "2").WithLocation(10, 27),
// (11,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// D2 d3 = () => ref null;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "null").WithLocation(11, 27),
// (12,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// D2 d4 = () => ref VoidMethod();
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(12, 27),
// (13,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference
// D1 d5 = () => ref P1;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithLocation(13, 27));
}
[Fact]
public void RefByValLocalParam()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
}
ref char Test1(char arg1, S1 arg2)
{
if (1.ToString() == null)
{
char l = default(char);
// valid
ref char r = ref l;
// invalid
return ref l;
}
if (2.ToString() == null)
{
S1 l = default(S1);
// valid
ref char r = ref l.x;
// invalid
return ref l.x;
}
if (3.ToString() == null)
{
// valid
ref char r = ref arg1;
// invalid
return ref arg1;
}
if (4.ToString() == null)
{
// valid
ref char r = ref arg2.x;
// invalid
return ref arg2.x;
}
throw null;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (18,24): error CS8168: Cannot return local 'l' by reference because it is not a ref local
// return ref l;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "l").WithArguments("l").WithLocation(18, 24),
// (28,24): error CS8169: Cannot return a member of local 'l' by reference because it is not a ref local
// return ref l.x;
Diagnostic(ErrorCode.ERR_RefReturnLocal2, "l").WithArguments("l").WithLocation(28, 24),
// (37,24): error CS8166: Cannot return a parameter by reference 'arg1' because it is not a ref parameter
// return ref arg1;
Diagnostic(ErrorCode.ERR_RefReturnParameter, "arg1").WithArguments("arg1").WithLocation(37, 24),
// (46,24): error CS8167: Cannot return a member of parameter 'arg2' by reference because it is not a ref or out parameter
// return ref arg2.x;
Diagnostic(ErrorCode.ERR_RefReturnParameter2, "arg2").WithArguments("arg2").WithLocation(46, 24)
);
}
[Fact]
public void RefByValLocalParam_UnsafeContext()
{
var text = @"
public unsafe class Test
{
public struct S1
{
public char x;
}
ref char Test1()
{
char l = default(char);
ref char r = ref l;
return ref l; // 1
}
ref char Test2()
{
S1 l = default(S1);
ref char r = ref l.x;
return ref l.x; // 2
}
ref char Test2(char arg1)
{
ref char r = ref arg1;
return ref arg1; // 3
}
ref char Test2(S1 arg2)
{
ref char r = ref arg2.x;
return ref arg2.x; // 4
}
}";
var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (13,20): warning CS9088: This returns local 'l' by reference but it is not a ref local
// return ref l; // 1
Diagnostic(ErrorCode.WRN_RefReturnLocal, "l").WithArguments("l").WithLocation(13, 20),
// (20,20): warning CS9089: This returns a member of local 'l' by reference but it is not a ref local
// return ref l.x; // 2
Diagnostic(ErrorCode.WRN_RefReturnLocal2, "l").WithArguments("l").WithLocation(20, 20),
// (26,20): warning CS9084: This returns a parameter by reference 'arg1' but it is not a ref parameter
// return ref arg1; // 3
Diagnostic(ErrorCode.WRN_RefReturnParameter, "arg1").WithArguments("arg1").WithLocation(26, 20),
// (32,20): warning CS9086: This returns by reference a member of parameter 'arg2' that is not a ref or out parameter
// return ref arg2.x; // 4
Diagnostic(ErrorCode.WRN_RefReturnParameter2, "arg2").WithArguments("arg2").WithLocation(32, 20)
);
}
[Fact]
public void RefReadonlyLocal()
{
var text = @"
public class Test
{
public struct S1
{
public int x;
}
ref char Test1()
{
foreach(var ro in ""qqq"")
{
ref char r = ref ro;
}
foreach(var ro in ""qqq"")
{
return ref ro;
}
foreach(var ro in new S1[1])
{
ref char r = ref ro.x;
}
foreach(var ro in new S1[1])
{
return ref ro.x;
}
throw null;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (13,30): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(13, 30),
// (18,24): error CS1657: Cannot use 'ro' as a ref or out value because it is a 'foreach iteration variable'
// return ref ro;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "ro").WithArguments("ro", "foreach iteration variable").WithLocation(18, 24),
// (23,30): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable'
// ref char r = ref ro.x;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(23, 30),
// (28,24): error CS1655: Cannot use fields of 'ro' as a ref or out value because it is a 'foreach iteration variable'
// return ref ro.x;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal2Cause, "ro.x").WithArguments("ro", "foreach iteration variable").WithLocation(28, 24)
);
}
[Fact]
public void RefRangeVar()
{
var text = @"
using System.Linq;
public class Test
{
public struct S1
{
public char x;
}
delegate ref char D1();
static void Test1()
{
var x = from ch in ""qqq""
select(D1)(() => ref ch);
var y = from s in new S1[10]
select(D1)(() => ref s.x);
}
}";
var comp = CreateCompilation(text, targetFramework: TargetFramework.Empty, references: new[] { MscorlibRef, SystemCoreRef });
comp.VerifyDiagnostics(
// (16,34): error CS8159: Cannot return the range variable 'ch' by reference
// select(D1)(() => ref ch);
Diagnostic(ErrorCode.ERR_RefReturnRangeVariable, "ch").WithArguments("ch").WithLocation(16, 34),
// (19,34): error CS8159: Cannot return the range variable 's' by reference
// select(D1)(() => ref s.x);
Diagnostic(ErrorCode.ERR_RefReturnRangeVariable, "s.x").WithArguments("s").WithLocation(19, 34)
);
}
[Fact]
public void RefMethodGroup()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
}
delegate ref char D1();
static ref char Test1()
{
ref char r = ref M;
ref char r1 = ref MR;
if (1.ToString() != null)
{
return ref M;
}
else
{
return ref MR;
}
}
static char M()
{
return default(char);
}
static ref char MR()
{
return ref (new char[1])[0];
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (14,26): error CS1657: Cannot use 'M' as a ref or out value because it is a 'method group'
// ref char r = ref M;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "M").WithArguments("M", "method group").WithLocation(14, 26),
// (15,27): error CS1657: Cannot use 'MR' as a ref or out value because it is a 'method group'
// ref char r1 = ref MR;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "MR").WithArguments("MR", "method group").WithLocation(15, 27),
// (19,24): error CS1657: Cannot use 'M' as a ref or out value because it is a 'method group'
// return ref M;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "M").WithArguments("M", "method group").WithLocation(19, 24),
// (23,24): error CS1657: Cannot use 'MR' as a ref or out value because it is a 'method group'
// return ref MR;
Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "MR").WithArguments("MR", "method group").WithLocation(23, 24)
);
}
[Fact]
public void RefReadonlyField()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
}
public static readonly char s1;
public static readonly S1 s2;
public readonly char i1;
public readonly S1 i2;
public Test()
{
if (1.ToString() != null)
{
// not an error
ref char temp = ref i1;
temp.ToString();
}
else
{
// not an error
ref char temp = ref i2.x;
temp.ToString();
}
if (1.ToString() != null)
{
// error
ref char temp = ref s1;
temp.ToString();
}
else
{
// error
ref char temp = ref s2.x;
temp.ToString();
}
}
static Test()
{
if (1.ToString() != null)
{
// not an error
ref char temp = ref s1;
temp.ToString();
}
else
{
// not an error
ref char temp = ref s2.x;
temp.ToString();
}
}
ref char Test1()
{
if (1.ToString() != null)
{
ref char temp = ref i1;
temp.ToString();
return ref i1;
}
else
{
ref char temp = ref i2.x;
temp.ToString();
return ref i2.x;
}
}
ref char Test2()
{
if (1.ToString() != null)
{
ref char temp = ref s1;
temp.ToString();
return ref s1;
}
else
{
ref char temp = ref s2.x;
temp.ToString();
return ref s2.x;
}
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (33,33): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "s1").WithLocation(33, 33),
// (39,33): error CS1651: Fields of static readonly field 'Test.s2' cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s2.x;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(39, 33),
// (65,33): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// ref char temp = ref i1;
Diagnostic(ErrorCode.ERR_RefReadonly, "i1").WithLocation(65, 33),
// (68,24): error CS8160: A readonly field cannot be returned by writable reference
// return ref i1;
Diagnostic(ErrorCode.ERR_RefReturnReadonly, "i1").WithLocation(68, 24),
// (72,33): error CS1649: Members of readonly field 'Test.i2' cannot be used as a ref or out value (except in a constructor)
// ref char temp = ref i2.x;
Diagnostic(ErrorCode.ERR_RefReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(72, 33),
// (75,24): error CS8162: Members of readonly field 'Test.i2' cannot be returned by writable reference
// return ref i2.x;
Diagnostic(ErrorCode.ERR_RefReturnReadonly2, "i2.x").WithArguments("Test.i2").WithLocation(75, 24),
// (83,33): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s1;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "s1").WithLocation(83, 33),
// (86,24): error CS8161: A static readonly field cannot be returned by writable reference
// return ref s1;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic, "s1").WithLocation(86, 24),
// (90,33): error CS1651: Fields of static readonly field 'Test.s2' cannot be used as a ref or out value (except in a static constructor)
// ref char temp = ref s2.x;
Diagnostic(ErrorCode.ERR_RefReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(90, 33),
// (93,24): error CS8163: Fields of static readonly field 'Test.s2' cannot be returned by writable reference
// return ref s2.x;
Diagnostic(ErrorCode.ERR_RefReturnReadonlyStatic2, "s2.x").WithArguments("Test.s2").WithLocation(93, 24)
);
}
[Fact]
public void RefReadonlyCall()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
public ref S1 GooS()
{
return ref this;
}
public ref char Goo()
{
return ref x;
}
public ref char Goo1()
{
return ref this.x;
}
}
static ref T Goo<T>(ref T arg)
{
return ref arg;
}
static ref char Test1()
{
char M1 = default(char);
S1 M2 = default(S1);
if (1.ToString() != null)
{
return ref Goo(ref M1);
}
if (2.ToString() != null)
{
return ref Goo(ref M2.x);
}
if (3.ToString() != null)
{
return ref Goo(ref M2).x;
}
else
{
return ref M2.Goo();
}
}
public class C
{
public ref C M()
{
return ref this;
}
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (10,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(10, 24),
// (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref x;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithLocation(15, 24),
// (20,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref this.x;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithLocation(20, 24),
// (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local
// return ref Goo(ref M1);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32),
// (36,24): error CS8347: Cannot use a result of 'Test.Goo<char>(ref char)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M1);
Diagnostic(ErrorCode.ERR_EscapeCall, "Goo(ref M1)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(36, 24),
// (41,32): error CS8169: Cannot return a member of local 'M2' by reference because it is not a ref local
// return ref Goo(ref M2.x);
Diagnostic(ErrorCode.ERR_RefReturnLocal2, "M2").WithArguments("M2").WithLocation(41, 32),
// (41,24): error CS8347: Cannot use a result of 'Test.Goo<char>(ref char)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M2.x);
Diagnostic(ErrorCode.ERR_EscapeCall, "Goo(ref M2.x)").WithArguments("Test.Goo<char>(ref char)", "arg").WithLocation(41, 24),
// (46,32): error CS8168: Cannot return local 'M2' by reference because it is not a ref local
// return ref Goo(ref M2).x;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "M2").WithArguments("M2").WithLocation(46, 32),
// (46,24): error CS8348: Cannot use a member of result of 'Test.Goo<Test.S1>(ref Test.S1)' in this context because it may expose variables referenced by parameter 'arg' outside of their declaration scope
// return ref Goo(ref M2).x;
Diagnostic(ErrorCode.ERR_EscapeCall2, "Goo(ref M2)").WithArguments("Test.Goo<Test.S1>(ref Test.S1)", "arg").WithLocation(46, 24),
// (58,24): error CS8354: Cannot return 'this' by reference.
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(58, 24)
);
}
[Fact]
public void RefReturnUnreturnableLocalParam()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
}
ref char Test1(char arg1, S1 arg2)
{
if (1.ToString() == null)
{
char l = default(char);
// valid
ref char r = ref l;
// invalid
return ref r;
}
if (2.ToString() == null)
{
S1 l = default(S1);
// valid
ref char r = ref l.x;
// invalid
return ref r;
}
if (21.ToString() == null)
{
S1 l = default(S1);
// valid
ref var r = ref l;
// invalid
return ref r.x;
}
if (3.ToString() == null)
{
// valid
ref char r = ref arg1;
// invalid
return ref r;
}
if (4.ToString() == null)
{
// valid
ref char r = ref arg2.x;
// invalid
return ref r;
}
if (41.ToString() == null)
{
// valid
ref S1 r = ref arg2;
// invalid
return ref r.x;
}
throw null;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (18,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(18, 24),
// (28,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(28, 24),
// (38,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference
// return ref r.x;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(38, 24),
// (47,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(47, 24),
// (56,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(56, 24),
// (65,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference
// return ref r.x;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(65, 24)
);
}
[Fact]
public void RefReturnUnreturnableLocalParam_UnsafeContext()
{
var text = @"
public unsafe class Test
{
public struct S1
{
public char x;
}
ref char Test1()
{
char l = default(char);
ref char r = ref l;
return ref r; // 1
}
ref char Test2()
{
S1 l = default(S1);
ref char r = ref l.x;
return ref r; // 2
}
ref char Test3()
{
S1 l = default(S1);
ref var r = ref l;
return ref r.x; // 3
}
ref char Test4(char arg1)
{
ref char r = ref arg1;
return ref r; // 4
}
ref char Test5(S1 arg2)
{
ref char r = ref arg2.x;
return ref r; // 5
}
ref char Test6(S1 arg2)
{
ref S1 r = ref arg2;
return ref r.x; // 6
}
}";
var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (13,20): warning CS9079: Local 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r; // 1
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(13, 20),
// (20,20): warning CS9079: Local 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r; // 2
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(20, 20),
// (27,20): warning CS9080: A member of 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r.x; // 3
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(27, 20),
// (33,20): warning CS9079: Local 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r; // 4
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(33, 20),
// (39,20): warning CS9079: Local 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r; // 5
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(39, 20),
// (45,20): warning CS9080: A member of 'r' is returned by reference but was initialized to a value that cannot be returned by reference
// return ref r.x; // 6
Diagnostic(ErrorCode.WRN_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(45, 20)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Test.Test1", @"
{
// Code size 12 (0xc)
.maxstack 1
.locals init (char V_0, //l
char& V_1, //r
char& V_2)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloca.s V_0
IL_0005: stloc.1
IL_0006: ldloc.1
IL_0007: stloc.2
IL_0008: br.s IL_000a
IL_000a: ldloc.2
IL_000b: ret
}
");
verifier.VerifyIL("Test.Test6", @"
{
// Code size 15 (0xf)
.maxstack 1
.locals init (Test.S1& V_0, //r
char& V_1)
IL_0000: nop
IL_0001: ldarga.s V_1
IL_0003: stloc.0
IL_0004: ldloc.0
IL_0005: ldflda ""char Test.S1.x""
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
}
");
}
[Fact]
public void RefAssignUnreturnableLocalParam_UnsafeContext()
{
var text = @"
public unsafe class Test
{
public struct S1
{
public char x;
}
void Test1()
{
char c = default;
ref char outer = ref c;
{
char l = default;
ref char r = ref l;
outer = ref r; // 1
}
}
}";
var comp = CreateCompilation(text, options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (16,13): warning CS9082: The right-hand-side expression 'r' has a narrower escape scope than the left-hand-side expression 'outer' in ref-assignment.
// outer = ref r; // 1
Diagnostic(ErrorCode.WRN_RefAssignNarrower, "outer = ref r").WithArguments("outer", "r").WithLocation(16, 13)
);
var verifier = CompileAndVerify(comp, verify: Verification.Skipped);
verifier.VerifyIL("Test.Test1", @"
{
// Code size 16 (0x10)
.maxstack 1
.locals init (char V_0, //c
char& V_1, //outer
char V_2, //l
char& V_3) //r
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldloca.s V_0
IL_0005: stloc.1
IL_0006: nop
IL_0007: ldc.i4.0
IL_0008: stloc.2
IL_0009: ldloca.s V_2
IL_000b: stloc.3
IL_000c: ldloc.3
IL_000d: stloc.1
IL_000e: nop
IL_000f: ret
}
");
}
[Fact]
public void RefReturnSelfReferringRef()
{
var text = @"
public class Test
{
public struct S1
{
public char x;
}
ref char Goo(ref char a, ref char b)
{
return ref a;
}
ref char Test1(char arg1, S1 arg2)
{
if (1.ToString() == null)
{
ref char r = ref r;
return ref r; //1
}
if (2.ToString() == null)
{
ref S1 r = ref r;
return ref r.x; //2
}
if (3.ToString() == null)
{
ref char a = ref (new char[1])[0];
ref char invalid = ref Goo(ref a, ref a);
// valid
return ref r;
}
if (4.ToString() == null)
{
ref char a = ref (new char[1])[0];
ref char valid = ref Goo(ref a, ref arg1);
// valid
return ref valid; //4
}
if (5.ToString() == null)
{
ref char a = ref (new char[1])[0];
ref char r = ref Goo(ref a, ref r);
// invalid
return ref r; //5
}
throw null;
}
}";
var comp = CreateCompilation(text);
comp.VerifyDiagnostics(
// (19,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r; //1
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(19, 24),
// (25,24): error CS8158: Cannot return by reference a member of 'r' because it was initialized to a value that cannot be returned by reference
// return ref r.x; //2
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal2, "r").WithArguments("r").WithLocation(25, 24),
// (34,24): error CS0103: The name 'r' does not exist in the current context
// return ref r;
Diagnostic(ErrorCode.ERR_NameNotInContext, "r").WithArguments("r").WithLocation(34, 24),
// (43,24): error CS8157: Cannot return 'valid' by reference because it was initialized to a value that cannot be returned by reference
// return ref valid; //4
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "valid").WithArguments("valid").WithLocation(43, 24),
// (52,24): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
// return ref r; //5
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(52, 24),
// (18,30): error CS0165: Use of unassigned local variable 'r'
// ref char r = ref r;
Diagnostic(ErrorCode.ERR_UseDefViolation, "r").WithArguments("r").WithLocation(18, 30),
// (24,28): error CS0165: Use of unassigned local variable 'r'
// ref S1 r = ref r;
Diagnostic(ErrorCode.ERR_UseDefViolation, "r").WithArguments("r").WithLocation(24, 28),
// (49,45): error CS0165: Use of unassigned local variable 'r'
// ref char r = ref Foo(ref a, ref r);
Diagnostic(ErrorCode.ERR_UseDefViolation, "r").WithArguments("r").WithLocation(49, 45)
);
}
[Fact]
public void RefReturnNested()
{
var text = @"
public class Test
{
public static void Main()
{
ref char Goo(ref char a, ref char b)
{
// valid
return ref a;
}
char Goo1(ref char a, ref char b)
{
return ref b;
}
ref char Goo2(ref char c, ref char b)
{
return c;
}
}
}";
var options = TestOptions.Regular;
var comp = CreateCompilationWithMscorlib461(text, parseOptions: options);
comp.VerifyDiagnostics(
// (14,13): error CS8149: By-reference returns may only be used in methods that return by reference
// return ref b;
Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(14, 13),
// (19,13): error CS8150: By-value returns may only be used in methods that return by value
// return c;
Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(19, 13),
// (6,18): warning CS8321: The local function 'Goo' is declared but never used
// ref char Goo(ref char a, ref char b)
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo").WithArguments("Goo").WithLocation(6, 18),
// (12,14): warning CS8321: The local function 'Goo1' is declared but never used
// char Goo1(ref char a, ref char b)
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo1").WithArguments("Goo1").WithLocation(12, 14),
// (17,18): warning CS8321: The local function 'Goo2' is declared but never used
// ref char Goo2(ref char c, ref char b)
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo2").WithArguments("Goo2").WithLocation(17, 18));
}
[Fact]
public void RefReturnNestedArrow()
{
var text = @"
public class Test
{
public static void Main()
{
// valid
ref char Goo(ref char a, ref char b) => ref a;
char Goo1(ref char a, ref char b) => ref b;
ref char Goo2(ref char c, ref char b) => c;
var arr = new int[1];
ref var r = ref arr[0];
ref char Moo1(ref char a, ref char b) => ref r;
char Moo3(ref char a, ref char b) => r;
}
}";
var options = TestOptions.Regular;
var comp = CreateCompilationWithMscorlib461(text, parseOptions: options);
comp.VerifyDiagnostics(
// (9,50): error CS8149: By-reference returns may only be used in methods that return by reference
// char Goo1(ref char a, ref char b) => ref b;
Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "b").WithLocation(9, 50),
// (11,50): error CS8150: By-value returns may only be used in methods that return by value
// ref char Goo2(ref char c, ref char b) => c;
Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "c").WithLocation(11, 50),
// (16,54): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression
// ref char Moo1(ref char a, ref char b) => ref r;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(16, 54),
// (17,46): error CS8175: Cannot use ref local 'r' inside an anonymous method, lambda expression, or query expression
// char Moo3(ref char a, ref char b) => r;
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "r").WithArguments("r").WithLocation(17, 46),
// (7,18): warning CS8321: The local function 'Goo' is declared but never used
// ref char Goo(ref char a, ref char b) => ref a;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo").WithArguments("Goo").WithLocation(7, 18),
// (9,14): warning CS8321: The local function 'Goo1' is declared but never used
// char Goo1(ref char a, ref char b) => ref b;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo1").WithArguments("Goo1").WithLocation(9, 14),
// (11,18): warning CS8321: The local function 'Goo2' is declared but never used
// ref char Goo2(ref char c, ref char b) => c;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Goo2").WithArguments("Goo2").WithLocation(11, 18),
// (16,18): warning CS8321: The local function 'Moo1' is declared but never used
// ref char Moo1(ref char a, ref char b) => ref r;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Moo1").WithArguments("Moo1").WithLocation(16, 18),
// (17,14): warning CS8321: The local function 'Moo3' is declared but never used
// char Moo3(ref char a, ref char b) => r;
Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Moo3").WithArguments("Moo3").WithLocation(17, 14)
);
}
[Fact, WorkItem(13062, "https://github.com/dotnet/roslyn/issues/13062")]
public void NoRefInIndex()
{
var text = @"
class C
{
void F(object[] a, object[,] a2, int i)
{
int j;
j = a[ref i]; // error 1
j = a[out i]; // error 2
j = this[ref i]; // error 3
j = a2[i, out i]; // error 4
j = a2[i, ref i]; // error 5
j = a2[ref i, out i]; // error 6
}
public int this[int i] => 1;
}
";
CreateCompilationWithMscorlib461(text).VerifyDiagnostics(
// (7,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)
// j = a[ref i]; // error 1
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a[ref i]").WithArguments("object", "int").WithLocation(7, 13),
// (7,19): error CS1615: Argument 1 may not be passed with the 'ref' keyword
// j = a[ref i]; // error 1
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("1", "ref").WithLocation(7, 19),
// (8,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)
// j = a[out i]; // error 2
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a[out i]").WithArguments("object", "int").WithLocation(8, 13),
// (8,19): error CS1615: Argument 1 may not be passed with the 'out' keyword
// j = a[out i]; // error 2
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("1", "out").WithLocation(8, 19),
// (9,22): error CS1615: Argument 1 may not be passed with the 'ref' keyword
// j = this[ref i]; // error 3
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("1", "ref").WithLocation(9, 22),
// (10,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)
// j = a2[i, out i]; // error 4
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a2[i, out i]").WithArguments("object", "int").WithLocation(10, 13),
// (10,23): error CS1615: Argument 2 may not be passed with the 'out' keyword
// j = a2[i, out i]; // error 4
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("2", "out").WithLocation(10, 23),
// (11,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)
// j = a2[i, ref i]; // error 5
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a2[i, ref i]").WithArguments("object", "int").WithLocation(11, 13),
// (11,23): error CS1615: Argument 2 may not be passed with the 'ref' keyword
// j = a2[i, ref i]; // error 5
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("2", "ref").WithLocation(11, 23),
// (12,13): error CS0266: Cannot implicitly convert type 'object' to 'int'. An explicit conversion exists (are you missing a cast?)
// j = a2[ref i, out i]; // error 6
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "a2[ref i, out i]").WithArguments("object", "int").WithLocation(12, 13),
// (12,20): error CS1615: Argument 1 may not be passed with the 'ref' keyword
// j = a2[ref i, out i]; // error 6
Diagnostic(ErrorCode.ERR_BadArgExtraRef, "i").WithArguments("1", "ref").WithLocation(12, 20)
);
}
[Fact, WorkItem(14174, "https://github.com/dotnet/roslyn/issues/14174")]
public void RefDynamicBinding()
{
var text = @"
class C
{
static object[] arr = new object[] { ""f"" };
static void Main(string[] args)
{
System.Console.Write(arr[0].ToString());
RefParam(ref arr[0]);
System.Console.Write(arr[0].ToString());
ref dynamic x = ref arr[0];
x = ""o"";
System.Console.Write(arr[0].ToString());
RefReturn() = ""g"";
System.Console.Write(arr[0].ToString());
}
static void RefParam(ref dynamic p)
{
p = ""r"";
}
static ref dynamic RefReturn()
{
return ref arr[0];
}
}
";
CompileAndVerify(text,
expectedOutput: "frog",
references: new[] { CSharpRef }).VerifyDiagnostics();
}
[Fact]
public void RefQueryClause()
{
// a "ref" may not precede the expression of a query clause...
// simply because the grammar doesn't permit it. Here we check
// that the situation is diagnosed, either syntactically or semantically.
// The precise diagnostics are not important for the purposes of this test.
var text = @"
class C
{
static void Main(string[] args)
{
var a = new[] { 1, 2, 3, 4 };
bool b = true;
int i = 0;
{ var za = from x in a select ref x; } // error 1
{ var zc = from x in a from y in ref a select x; } // error2
{ var zd = from x in a from int y in ref a select x; } // error 3
{ var ze = from x in a from y in ref a where true select x; } // error 4
{ var zf = from x in a from int y in ref a where true select x; } // error 5
{ var zg = from x in a let y = ref a select x; } // error 6
{ var zh = from x in a where ref b select x; } // error 7
{ var zi = from x in a join y in ref a on x equals y select x; } // error 8 (not lambda case)
{ var zj = from x in a join y in a on ref i equals y select x; } // error 9
{ var zk = from x in a join y in a on x equals ref i select x; } // error 10
{ var zl = from x in a orderby ref i select x; } // error 11
{ var zm = from x in a orderby x, ref i select x; } // error 12
{ var zn = from x in a group ref i by x; } // error 13
{ var zo = from x in a group x by ref i; } // error 14
}
public static T M<T>(T x, out T z) => z = x;
public C Select(RefFunc<C, C> c1) => this;
public C SelectMany(RefFunc<C, C> c1, RefFunc<C, C, C> c2) => this;
public C Cast<T>() => this;
}
public delegate ref TR RefFunc<T1, TR>(T1 t1);
public delegate ref TR RefFunc<T1, T2, TR>(T1 t1, T2 t2);
";
CreateCompilationWithMscorlib40AndSystemCore(text)
.GetDiagnostics()
// It turns out each of them is diagnosed with ErrorCode.ERR_InvalidExprTerm in the midst
// of a flurry of other syntax errors.
.Where(d => d.Code == (int)ErrorCode.ERR_InvalidExprTerm)
.Verify(
// (9,39): error CS1525: Invalid expression term 'ref'
// { var za = from x in a select ref x; } // error 1
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref x").WithArguments("ref").WithLocation(9, 39),
// (10,42): error CS1525: Invalid expression term 'ref'
// { var zc = from x in a from y in ref a select x; } // error2
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(10, 42),
// (11,46): error CS1525: Invalid expression term 'ref'
// { var zd = from x in a from int y in ref a select x; } // error 3
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(11, 46),
// (12,42): error CS1525: Invalid expression term 'ref'
// { var ze = from x in a from y in ref a where true select x; } // error 4
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(12, 42),
// (13,46): error CS1525: Invalid expression term 'ref'
// { var zf = from x in a from int y in ref a where true select x; } // error 5
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(13, 46),
// (14,40): error CS1525: Invalid expression term 'ref'
// { var zg = from x in a let y = ref a select x; } // error 6
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(14, 40),
// (15,38): error CS1525: Invalid expression term 'ref'
// { var zh = from x in a where ref b select x; } // error 7
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref b").WithArguments("ref").WithLocation(15, 38),
// (16,42): error CS1525: Invalid expression term 'ref'
// { var zi = from x in a join y in ref a on x equals y select x; } // error 8 (not lambda case)
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a").WithArguments("ref").WithLocation(16, 42),
// (17,47): error CS1525: Invalid expression term 'ref'
// { var zj = from x in a join y in a on ref i equals y select x; } // error 9
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(17, 47),
// (18,56): error CS1525: Invalid expression term 'ref'
// { var zk = from x in a join y in a on x equals ref i select x; } // error 10
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(18, 56),
// (19,40): error CS1525: Invalid expression term 'ref'
// { var zl = from x in a orderby ref i select x; } // error 11
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(19, 40),
// (20,43): error CS1525: Invalid expression term 'ref'
// { var zm = from x in a orderby x, ref i select x; } // error 12
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(20, 43),
// (21,38): error CS1525: Invalid expression term 'ref'
// { var zn = from x in a group ref i by x; } // error 13
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(21, 38),
// (22,43): error CS1525: Invalid expression term 'ref'
// { var zo = from x in a group x by ref i; } // error 14
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref i").WithArguments("ref").WithLocation(22, 43)
);
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseYieldReturnInAReturnByRefFunction()
{
var code = @"
class TestClass
{
int x = 0;
ref int TestFunction()
{
yield return x;
ref int localFunction()
{
yield return x;
}
yield return localFunction();
}
}";
CreateCompilation(code).VerifyDiagnostics(
// (9,17): error CS8154: The body of 'localFunction()' cannot be an iterator block because 'localFunction()' returns by reference
// ref int localFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "localFunction").WithArguments("localFunction()").WithLocation(9, 17),
// (5,13): error CS8154: The body of 'TestClass.TestFunction()' cannot be an iterator block because 'TestClass.TestFunction()' returns by reference
// ref int TestFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "TestFunction").WithArguments("TestClass.TestFunction()").WithLocation(5, 13));
}
[Fact]
public void CannotUseYieldReturnInAReturnByRefFunction_InIfBlock()
{
var code = @"
class TestClass
{
int x = 0;
ref int TestFunction()
{
if (true)
{
yield return x;
}
ref int localFunction()
{
if (true)
{
yield return x;
}
}
yield return localFunction();
}
}";
CreateCompilation(code).VerifyDiagnostics(
// (12,17): error CS8154: The body of 'localFunction()' cannot be an iterator block because 'localFunction()' returns by reference
// ref int localFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "localFunction").WithArguments("localFunction()").WithLocation(12, 17),
// (5,13): error CS8154: The body of 'TestClass.TestFunction()' cannot be an iterator block because 'TestClass.TestFunction()' returns by reference
// ref int TestFunction()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "TestFunction").WithArguments("TestClass.TestFunction()").WithLocation(5, 13));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseRefReturnInExpressionTree_ParenthesizedLambdaExpression()
{
var code = @"
using System.Linq.Expressions;
class TestClass
{
int x = 0;
delegate ref int RefReturnIntDelegate(int y);
void TestFunction()
{
Expression<RefReturnIntDelegate> lambda = (y) => ref x;
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyDiagnostics(
// (11,51): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<RefReturnIntDelegate> lambda = (y) => ref x;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(y) => ref x").WithLocation(11, 51));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseRefReturnInExpressionTree_SimpleLambdaExpression()
{
var code = @"
using System.Linq.Expressions;
class TestClass
{
int x = 0;
delegate ref int RefReturnIntDelegate(int y);
void TestFunction()
{
Expression<RefReturnIntDelegate> lambda = y => ref x;
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyDiagnostics(
// (11,51): error CS8155: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<RefReturnIntDelegate> lambda = y => ref x;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "y => ref x").WithLocation(11, 51));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotCallExpressionThatReturnsByRefInExpressionTree_01()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace TestRefReturns
{
class TestClass
{
int x = 0;
ref int RefReturnFunction()
{
return ref x;
}
ref int RefReturnProperty
{
get { return ref x; }
}
ref int this[int y]
{
get { return ref x; }
}
int TakeRefFunction(ref int y)
{
return y;
}
void TestFunction()
{
Expression<Func<int>> lambda1 = () => TakeRefFunction(ref RefReturnFunction());
Expression<Func<int>> lambda2 = () => TakeRefFunction(ref RefReturnProperty);
Expression<Func<int>> lambda3 = () => TakeRefFunction(ref this[0]);
}
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyEmitDiagnostics(
// (32,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda1 = () => TakeRefFunction(ref RefReturnFunction());
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "RefReturnFunction()").WithLocation(32, 71),
// (33,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda2 = () => TakeRefFunction(ref RefReturnProperty);
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "RefReturnProperty").WithLocation(33, 71),
// (34,71): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<Func<int>> lambda3 = () => TakeRefFunction(ref this[0]);
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "this[0]").WithLocation(34, 71));
}
[WorkItem(19930, "https://github.com/dotnet/roslyn/issues/19930")]
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotRefReturnQueryRangeVariable()
{
var code = @"
using System.Linq;
class TestClass
{
delegate ref char RefCharDelegate();
void TestMethod()
{
var x = from c in ""TestValue"" select (RefCharDelegate)(() => ref c);
}
delegate ref readonly char RoRefCharDelegate();
void TestMethod1()
{
var x = from c in ""TestValue"" select (RoRefCharDelegate)(() => ref c);
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyDiagnostics(
// (8,74): error CS8159: Cannot return the range variable 'c' by reference
// var x = from c in "TestValue" select (RefCharDelegate)(() => ref c);
Diagnostic(ErrorCode.ERR_RefReturnRangeVariable, "c").WithArguments("c").WithLocation(8, 74),
// (14,76): error CS8159: Cannot return the range variable 'c' by reference
// var x = from c in "TestValue" select (RoRefCharDelegate)(() => ref c);
Diagnostic(ErrorCode.ERR_RefReturnRangeVariable, "c").WithArguments("c").WithLocation(14, 76)
);
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotAssignRefInNonIdentityConversion()
{
var code = @"
using System;
using System.Collections.Generic;
class TestClass
{
int intVar = 0;
string stringVar = ""TEST"";
void TestMethod()
{
ref int? nullableConversion = ref intVar;
ref dynamic dynamicConversion = ref intVar;
ref IEnumerable<char> enumerableConversion = ref stringVar;
ref IFormattable interpolatedStringConversion = ref stringVar;
}
}";
CreateCompilation(code).VerifyDiagnostics(
// (12,43): error CS8173: The expression must be of type 'int?' because it is being assigned by reference
// ref int? nullableConversion = ref intVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "intVar").WithArguments("int?").WithLocation(12, 43),
// (13,45): error CS8173: The expression must be of type 'dynamic' because it is being assigned by reference
// ref dynamic dynamicConversion = ref intVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "intVar").WithArguments("dynamic").WithLocation(13, 45),
// (14,58): error CS8173: The expression must be of type 'IEnumerable<char>' because it is being assigned by reference
// ref IEnumerable<char> enumerableConversion = ref stringVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "stringVar").WithArguments("System.Collections.Generic.IEnumerable<char>").WithLocation(14, 58),
// (15,61): error CS8173: The expression must be of type 'IFormattable' because it is being assigned by reference
// ref IFormattable interpolatedStringConversion = ref stringVar;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "stringVar").WithArguments("System.IFormattable").WithLocation(15, 61));
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void IteratorMethodsCannotHaveRefLocals()
{
var code = @"
using System.Collections.Generic;
class TestClass
{
int x = 0;
IEnumerable<int> TestMethod()
{
ref int y = ref x;
yield return y;
IEnumerable<int> localFunction()
{
ref int z = ref x;
yield return z;
}
foreach(var item in localFunction())
{
yield return item;
}
}
}";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (8,17): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(8, 17),
// (13,21): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "z").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(13, 21));
CreateCompilation(code, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics();
CreateCompilation(code).VerifyEmitDiagnostics();
}
[Fact]
public void RefLocal_Iterator_LocalFunction_01()
{
var code = """
using System;
using System.Collections.Generic;
int x = 5;
foreach (var z in func())
{
Console.Write(z);
x++;
}
IEnumerable<int> func()
{
ref int y = ref x;
yield return y;
y = ref x;
yield return y;
}
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (14,13): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(14, 13));
var expectedOutput = "56";
CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular13).VerifyDiagnostics();
CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
public void RefLocal_Iterator_LocalFunction_02()
{
var code = """
using System.Collections.Generic;
int x = 5;
IEnumerable<int> func()
{
ref int y = ref x;
yield return y;
yield return y;
}
func();
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (7,13): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(7, 13));
var expectedDiagnostics = new[]
{
// (9,18): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
// yield return y;
Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(9, 18)
};
CreateCompilation(code, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void RefStruct_Iterator_LocalFunction_01()
{
var code = """
using System;
using System.Collections.Generic;
int x = 5;
foreach (var z in func())
{
Console.Write(z);
x++;
}
IEnumerable<int> func()
{
Span<int> y = new(ref x);
yield return y[0];
y = new(ref x);
yield return y[0];
}
""";
var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "56";
CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics();
CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics();
CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics();
}
[Fact]
public void RefStruct_Iterator_LocalFunction_02()
{
var code = """
using System;
using System.Collections.Generic;
int x = 5;
IEnumerable<int> func()
{
Span<int> y = new(ref x);
yield return y[0];
yield return y[0];
}
func();
""";
var expectedDiagnostics = new[]
{
// (10,18): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// yield return y[0];
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span<int>").WithLocation(10, 18)
};
CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(code, parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void AsyncMethodsCannotHaveRefLocals()
{
var code = @"
using System.Threading.Tasks;
class TestClass
{
int x = 0;
async Task TestMethod()
{
ref int y = ref x;
await Task.Run(async () =>
{
ref int z = ref x;
await Task.Delay(0);
});
}
}";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (8,17): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(8, 17),
// (11,21): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int z = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "z").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(11, 21));
CreateCompilation(code, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics();
CreateCompilation(code).VerifyEmitDiagnostics();
}
[Fact]
public void RefLocal_Async_LocalFunction_01()
{
var code = """
using System;
using System.Threading.Tasks;
int x = 5;
await func();
async Task func()
{
ref int y = ref x;
Console.Write(y);
await Task.Yield();
y = ref x;
Console.Write(y);
await Task.Yield();
}
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (10,13): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 13));
var expectedOutput = "55";
CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular13).VerifyDiagnostics();
CompileAndVerify(code, expectedOutput: expectedOutput).VerifyDiagnostics();
}
[Fact]
public void RefLocal_Async_LocalFunction_02()
{
var code = """
using System;
using System.Threading.Tasks;
int x = 5;
async Task func()
{
ref int y = ref x;
await Task.Yield();
Console.Write(y);
}
await func();
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (8,13): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// ref int y = ref x;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "y").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(8, 13));
var expectedDiagnostics = new[]
{
// (10,19): error CS9217: A 'ref' local cannot be preserved across 'await' or 'yield' boundary.
// Console.Write(y);
Diagnostic(ErrorCode.ERR_RefLocalAcrossAwait, "y").WithLocation(10, 19)
};
CreateCompilation(code, parseOptions: TestOptions.Regular13).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(code).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact]
public void RefStruct_Async_LocalFunction_01()
{
var code = """
using System;
using System.Threading.Tasks;
int x = 5;
await func();
async Task func()
{
Span<int> y = new(ref x);
Console.Write(y[0]);
await Task.Yield();
y = new(ref x);
Console.Write(y[0]);
await Task.Yield();
}
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics(
// (10,5): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// Span<int> y = new(ref x);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "Span<int>").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(10, 5));
var expectedOutput = ExecutionConditionUtil.IsDesktop ? null : "55";
CompileAndVerify(code, expectedOutput: expectedOutput, parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics();
CompileAndVerify(code, expectedOutput: expectedOutput, targetFramework: TargetFramework.Net70, verify: Verification.FailsPEVerify).VerifyDiagnostics();
}
[Fact]
public void RefStruct_Async_LocalFunction_02()
{
var code = """
using System;
using System.Threading.Tasks;
int x = 5;
async Task func()
{
Span<int> y = new(ref x);
await Task.Yield();
Console.Write(y[0]);
}
await func();
""";
CreateCompilation(code, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net70).VerifyDiagnostics(
// (8,5): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater.
// Span<int> y = new(ref x);
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "Span<int>").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(8, 5));
var expectedDiagnostics = new[]
{
// (10,19): error CS4007: Instance of type 'System.Span<int>' cannot be preserved across 'await' or 'yield' boundary.
// Console.Write(y[0]);
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "y").WithArguments("System.Span<int>").WithLocation(10, 19)
};
CreateCompilation(code, parseOptions: TestOptions.Regular13, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics);
CreateCompilation(code, targetFramework: TargetFramework.Net70).VerifyEmitDiagnostics(expectedDiagnostics);
}
[Fact, WorkItem(13073, "https://github.com/dotnet/roslyn/issues/13073")]
public void CannotUseAwaitExpressionInACallToAFunctionThatReturnsByRef()
{
var code = @"
using System;
using System.Threading.Tasks;
class TestClass
{
int x = 0;
ref int Save(int y)
{
x = y;
return ref x;
}
void Write(ref int y)
{
Console.WriteLine(y);
}
void Write(ref int y, int z)
{
Console.WriteLine(z);
}
async Task TestMethod()
{
// this is OK. `ref` is not spilled.
Write(ref Save(await Task.FromResult(0)));
// ERROR. `ref` is spilled because it must survive until after the second `await.
Write(ref Save(await Task.FromResult(0)), await Task.FromResult(1));
}
}";
CreateCompilationWithMscorlib461(code).VerifyEmitDiagnostics(
// (26,19): error CS8178: A reference returned by a call to 'TestClass.Save(int)' cannot be preserved across 'await' or 'yield' boundary.
// Write(ref Save(await Task.FromResult(0)), await Task.FromResult(1));
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "Save(await Task.FromResult(0))").WithArguments("TestClass.Save(int)").WithLocation(26, 19)
);
}
[Fact]
public void BadRefAssignByValueProperty()
{
var text = @"
class Program
{
static int P { get; set; }
static void M()
{
ref int rl = ref P;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// ref int rl = ref P;
Diagnostic(ErrorCode.ERR_RefProperty, "P").WithLocation(8, 26));
}
[Fact]
public void BadRefAssignByValueIndexer()
{
var text = @"
class Program
{
int this[int i] { get { return 0; } }
void M()
{
ref int rl = ref this[0];
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS0206: A non ref-returning property or indexer may not be used as an out or ref value
// ref int rl = ref this[0];
Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithLocation(8, 26));
}
[Fact]
public void BadRefAssignNonFieldEvent()
{
var text = @"
delegate void D();
class Program
{
event D d { add { } remove { } }
void M()
{
ref int rl = ref d;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (10,26): error CS0079: The event 'Program.d' can only appear on the left hand side of += or -=
// ref int rl = ref d;
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "d").WithArguments("Program.d").WithLocation(10, 26));
}
[Fact]
public void BadRefAssignReadonlyField()
{
var text = @"
class Program
{
readonly int i = 0;
void M()
{
ref int rl = ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS0192: A readonly field cannot be used as a ref or out value (except in a constructor)
// ref int rl = ref i;
Diagnostic(ErrorCode.ERR_RefReadonly, "i").WithLocation(8, 26));
}
[Fact]
public void BadRefAssignFieldReceiver()
{
var text = @"
struct Program
{
int i;
Program(int i)
{
this.i = i;
}
ref int M()
{
ref int rl = ref i;
return ref rl;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (14,20): error CS8157: Cannot return 'rl' by reference because it was initialized to a value that cannot be returned by reference
// return ref rl;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "rl").WithArguments("rl").WithLocation(14, 20)
);
}
[Fact]
public void BadRefAssignByValueCall()
{
var text = @"
class Program
{
static int L()
{
return 0;
}
static void M()
{
ref int rl = ref L();
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (11,26): error CS1510: A ref or out value must be an assignable variable
// ref int rl = ref L();
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "L()").WithLocation(11, 26)
);
}
[Fact]
public void BadRefAssignByValueDelegateInvocation()
{
var text = @"
delegate int D();
class Program
{
static void M(D d)
{
ref int rl = ref d();
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS1510: A ref or out value must be an assignable variable
// ref int rl = ref d();
Diagnostic(ErrorCode.ERR_RefLvalueExpected, "d()").WithLocation(8, 26)
);
}
[Fact]
public void BadRefAssignCallArgument()
{
var text = @"
class Program
{
static ref int M(ref int i)
{
int j = 0;
ref int rl = ref M(ref j);
return ref rl;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS8157: Cannot return 'rl' by reference because it was initialized to a value that cannot be returned by reference
// return ref rl;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "rl").WithArguments("rl").WithLocation(8, 20)
);
}
[Fact]
public void BadRefAssignThisReference()
{
var text = @"
class Program
{
void M()
{
ref int rl = ref this;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,26): error CS1605: Cannot use 'this' as a ref or out value because it is read-only
// ref int rl = ref this;
Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "this").WithArguments("this").WithLocation(6, 26)
);
}
[Fact]
public void BadRefAssignWrongType()
{
var text = @"
class Program
{
void M(ref long i)
{
ref int rl = ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,26): error CS8173: The expression must be of type 'int' because it is being assigned by reference
// ref int rl = ref i;
Diagnostic(ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion, "i").WithArguments("int").WithLocation(6, 26)
);
}
[Fact]
public void BadRefLocalCapturedInAnonymousMethod()
{
var text = @"
using System.Linq;
delegate int D();
class Program
{
static int field = 0;
static void M()
{
ref int rl = ref field;
var d = new D(delegate { return rl; });
d = new D(() => rl);
rl = (from v in new int[10] where v > rl select v).Single();
}
}
";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (13,41): error CS8930: Cannot use ref local 'rl' inside an anonymous method, lambda expression, or query expression
// var d = new D(delegate { return rl; });
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "rl").WithArguments("rl").WithLocation(13, 41),
// (14,25): error CS8930: Cannot use ref local 'rl' inside an anonymous method, lambda expression, or query expression
// d = new D(() => rl);
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "rl").WithArguments("rl").WithLocation(14, 25),
// (15,47): error CS8930: Cannot use ref local 'rl' inside an anonymous method, lambda expression, or query expression
// rl = (from v in new int[10] where v > rl select r1).Single();
Diagnostic(ErrorCode.ERR_AnonDelegateCantUseLocal, "rl").WithArguments("rl").WithLocation(15, 47));
}
[Fact]
public void BadRefLocalInAsyncMethod()
{
var text = @"
class Program
{
static int field = 0;
static async void Goo()
{
ref int i = ref field;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyEmitDiagnostics(
// (6,23): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
// static async void Goo()
Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "Goo").WithLocation(6, 23));
}
[Fact]
public void RefReturnAcrossAwaitExpression()
{
var code = """
using System.Threading.Tasks;
class Program
{
static int field = 1;
static async Task Main()
{
M1(ref GiveMeRef(), await M2());
}
static void M1(ref int i, int j) { }
static ref int GiveMeRef() => ref field;
static Task<int> M2() => Task.FromResult(field++);
}
""";
CreateCompilation(code).VerifyEmitDiagnostics(
// (9,16): error CS8178: A reference returned by a call to 'Program.GiveMeRef()' cannot be preserved across 'await' or 'yield' boundary.
// M1(ref GiveMeRef(), await M2());
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "GiveMeRef()").WithArguments("Program.GiveMeRef()").WithLocation(9, 16));
}
[Fact]
public void BadRefLocalInIteratorMethod()
{
var text = @"
using System.Collections;
class Program
{
static int field = 0;
static IEnumerable ObjEnumerable()
{
ref int i = ref field;
yield return new object();
}
}
";
CreateCompilationWithMscorlib46(text).VerifyEmitDiagnostics();
}
[Fact]
public void BadRefAssignByValueLocal()
{
var text = @"
class Program
{
static void M(ref int i)
{
int l = ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,13): error CS8922: Cannot initialize a by-value variable with a reference
// int l = ref i;
Diagnostic(ErrorCode.ERR_InitializeByValueVariableWithReference, "l = ref i").WithLocation(6, 13)
);
}
[Fact]
public void BadByValueInitRefLocal()
{
var text = @"
class Program
{
static void M(int i)
{
ref int rl = i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,17): error CS8921: Cannot initialize a by-reference variable with a value
// ref int rl = i;
Diagnostic(ErrorCode.ERR_InitializeByReferenceVariableWithValue, "rl = i").WithLocation(6, 17));
}
[Fact]
public void BadRefReturnParameter()
{
var text = @"
class Program
{
static ref int M(int i)
{
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,20): error CS8911: Cannot return or assign a reference to parameter 'i' because it is not a ref or out parameter
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(6, 20));
}
[Fact]
public void BadRefReturnLocal()
{
var text = @"
class Program
{
static ref int M()
{
int i = 0;
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (7,20): error CS8913: Cannot return or assign a reference to local 'i' because it is not a ref local
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnLocal, "i").WithArguments("i").WithLocation(7, 20));
}
[Fact]
public void BadRefReturnByValueProperty()
{
var text = @"
class Program
{
static int P { get; set; }
static ref int M()
{
return ref P;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference
// return ref P;
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P").WithLocation(8, 20));
}
[Fact]
public void BadRefReturnByValueIndexer()
{
var text = @"
class Program
{
int this[int i] { get { return 0; } }
ref int M()
{
return ref this[0];
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference
// return ref this[0];
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "this[0]").WithLocation(8, 20));
}
[Fact]
public void BadRefReturnNonFieldEvent()
{
var text = @"
delegate void D();
class Program
{
event D d { add { } remove { } }
ref int M()
{
return ref d;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (10,20): error CS0079: The event 'Program.d' can only appear on the left hand side of += or -=
// return ref d;
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "d").WithArguments("Program.d").WithLocation(10, 20));
}
[Fact]
public void BadRefReturnEventReceiver()
{
var text = @"
delegate void D();
struct Program
{
event D d;
ref D M()
{
return ref d;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (10,20): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref d;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "d").WithLocation(10, 20)
);
}
[Fact]
public void BadRefReturnReadonlyField()
{
var text = @"
class Program
{
readonly int i = 0;
ref int M()
{
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS8160: A readonly field cannot be returned by writable reference
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnReadonly, "i").WithLocation(8, 20)
);
}
[Fact]
public void BadRefReturnFieldReceiver()
{
var text = @"
struct Program
{
int i;
Program(int i)
{
this.i = i;
}
ref int M()
{
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (13,20): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "i").WithLocation(13, 20)
);
}
[Fact]
public void BadRefReturnByValueCall()
{
var text = @"
class Program
{
static int L()
{
return 0;
}
static ref int M()
{
return ref L();
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (11,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference
// return ref L();
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "L()").WithLocation(11, 20));
}
[Fact]
public void BadRefReturnByValueDelegateInvocation()
{
var text = @"
delegate int D();
class Program
{
static ref int M(D d)
{
return ref d();
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference
// return ref d();
Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "d()").WithLocation(8, 20));
}
[Fact]
public void BadRefReturnDelegateInvocationWithArguments()
{
var text = @"
delegate ref int D(ref int i, ref int j, object o);
class Program
{
static ref int M(D d, int i, int j, object o)
{
return ref d(ref i, ref j, o);
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (8,26): error CS8166: Cannot return a parameter by reference 'i' because it is not a ref parameter
// return ref d(ref i, ref j, o);
Diagnostic(ErrorCode.ERR_RefReturnParameter, "i").WithArguments("i").WithLocation(8, 26),
// (8,20): error CS8347: Cannot use a result of 'D.Invoke(ref int, ref int, object)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref d(ref i, ref j, o);
Diagnostic(ErrorCode.ERR_EscapeCall, "d(ref i, ref j, o)").WithArguments("D.Invoke(ref int, ref int, object)", "i").WithLocation(8, 20)
);
}
[Fact]
public void BadRefReturnCallArgument()
{
var text = @"
class Program
{
static ref int M(ref int i)
{
int j = 0;
return ref M(ref j);
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (7,26): error CS8168: Cannot return local 'j' by reference because it is not a ref local
// return ref M(ref j);
Diagnostic(ErrorCode.ERR_RefReturnLocal, "j").WithArguments("j").WithLocation(7, 26),
// (7,20): error CS8347: Cannot use a result of 'Program.M(ref int)' in this context because it may expose variables referenced by parameter 'i' outside of their declaration scope
// return ref M(ref j);
Diagnostic(ErrorCode.ERR_EscapeCall, "M(ref j)").WithArguments("Program.M(ref int)", "i").WithLocation(7, 20)
);
}
[Fact]
public void BadRefReturnStructThis()
{
var text = @"
struct Program
{
ref Program M()
{
return ref this;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,20): error CS8170: Struct members cannot return 'this' or other instance members by reference
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(6, 20));
}
[Fact]
public void BadRefReturnThisReference()
{
var text = @"
class Program
{
ref Program M()
{
return ref this;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,20): error CS8354: Cannot return 'this' by reference.
// return ref this;
Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(6, 20)
);
}
[Fact]
public void BadRefReturnWrongType()
{
var text = @"
class Program
{
ref int M(ref long i)
{
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,20): error CS8085: The return expression must be of type 'int' because this method returns by reference.
// return ref i;
Diagnostic(ErrorCode.ERR_RefReturnMustHaveIdentityConversion, "i").WithArguments("int").WithLocation(6, 20));
}
[Fact]
public void BadByRefReturnInByValueReturningMethod()
{
var text = @"
class Program
{
static int M(ref int i)
{
return ref i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,9): error CS8083: By-reference returns may only be used in by-reference returning methods.
// return ref i;
Diagnostic(ErrorCode.ERR_MustNotHaveRefReturn, "return").WithLocation(6, 9));
}
[Fact]
public void BadByValueReturnInByRefReturningMethod()
{
var text = @"
class Program
{
static ref int M(ref int i)
{
return i;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,9): error CS8084: By-value returns may only be used in by-value returning methods.
// return;
Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(6, 9));
}
[Fact]
public void BadEmptyReturnInByRefReturningMethod()
{
var text = @"
class Program
{
static ref int M(ref int i)
{
return;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (6,9): error CS8150: By-value returns may only be used in methods that return by value
// return;
Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(6, 9)
);
}
[ConditionalFact(typeof(NoUsedAssembliesValidation))] // The test hook is blocked by https://github.com/dotnet/roslyn/issues/39971
[WorkItem(39971, "https://github.com/dotnet/roslyn/issues/39971")]
public void BadIteratorReturnInRefReturningMethod()
{
var text = @"
using System.Collections;
using System.Collections.Generic;
class C
{
public ref IEnumerator ObjEnumerator()
{
yield return new object();
}
public ref IEnumerable ObjEnumerable()
{
yield return new object();
}
public ref IEnumerator<int> GenEnumerator()
{
yield return 0;
}
public ref IEnumerable<int> GenEnumerable()
{
yield return 0;
}
}
";
CreateCompilationWithMscorlib46(text).VerifyDiagnostics(
// (7,28): error CS8089: The body of 'C.ObjEnumerator()' cannot be an iterator block because 'C.ObjEnumerator()' returns by reference
// public ref IEnumerator ObjEnumerator()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "ObjEnumerator").WithArguments("C.ObjEnumerator()").WithLocation(7, 28),
// (12,28): error CS8089: The body of 'C.ObjEnumerable()' cannot be an iterator block because 'C.ObjEnumerable()' returns by reference
// public ref IEnumerable ObjEnumerable()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "ObjEnumerable").WithArguments("C.ObjEnumerable()").WithLocation(12, 28),
// (17,33): error CS8089: The body of 'C.GenEnumerator()' cannot be an iterator block because 'C.GenEnumerator()' returns by reference
// public ref IEnumerator<int> GenEnumerator()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "GenEnumerator").WithArguments("C.GenEnumerator()").WithLocation(17, 33),
// (22,33): error CS8089: The body of 'C.GenEnumerable()' cannot be an iterator block because 'C.GenEnumerable()' returns by reference
// public ref IEnumerable<int> GenEnumerable()
Diagnostic(ErrorCode.ERR_BadIteratorReturnRef, "GenEnumerable").WithArguments("C.GenEnumerable()").WithLocation(22, 33));
}
[Fact]
public void BadRefReturnInExpressionTree()
{
var text = @"
using System.Linq.Expressions;
delegate ref int D();
delegate ref int E(int i);
class C
{
static int field = 0;
static void M()
{
Expression<D> d = () => ref field;
Expression<E> e = (int i) => ref field;
}
}
";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyDiagnostics(
// (13,27): error CS8090: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<D> d = () => ref field;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "() => ref field").WithLocation(13, 27),
// (14,27): error CS8090: Lambda expressions that return by reference cannot be converted to expression trees
// Expression<E> e = (int i) => ref field;
Diagnostic(ErrorCode.ERR_BadRefReturnExpressionTree, "(int i) => ref field").WithLocation(14, 27));
}
[Fact]
public void BadRefReturningCallInExpressionTree()
{
var text = @"
using System.Linq.Expressions;
delegate int D(C c);
class C
{
int field = 0;
ref int P { get { return ref @field; } }
ref int this[int i] { get { return ref field; } }
ref int M() { return ref field; }
static void M1()
{
Expression<D> e = c => c.P;
e = c => c[0];
e = c => c.M();
}
}
";
CreateCompilationWithMscorlib40AndSystemCore(text).VerifyEmitDiagnostics(
// (16,32): error CS8091: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Expression<D> e = c => c.P;
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "c.P").WithLocation(16, 32),
// (17,18): error CS8091: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// e = c => c[0];
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "c[0]").WithLocation(17, 18),
// (18,18): error CS8091: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// e = c => c.M();
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "c.M()").WithLocation(18, 18));
}
[Fact]
public void BadRefReturningCallWithAwait()
{
var text = @"
using System.Threading.Tasks;
struct S
{
static S s = new S();
public static ref S Instance { get { return ref s; } }
public int Echo(int i)
{
return i;
}
}
class C
{
ref int Assign(ref int loc, int val)
{
loc = val;
return ref loc;
}
public async Task<int> Do(int i)
{
if (i == 0)
{
return 0;
}
int temp = 0;
var a = S.Instance.Echo(await Do(i - 1));
var b = Assign(ref Assign(ref temp, 0), await Do(i - 1));
return a + b;
}
}
";
CreateCompilationWithMscorlib461(text).VerifyEmitDiagnostics(
// (32,17): error CS8178: A reference returned by a call to 'S.Instance.get' cannot be preserved across 'await' or 'yield' boundary.
// var a = S.Instance.Echo(await Do(i - 1));
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "S.Instance").WithArguments("S.Instance.get").WithLocation(32, 17),
// (33,28): error CS8178: A reference returned by a call to 'C.Assign(ref int, int)' cannot be preserved across 'await' or 'yield' boundary.
// var b = Assign(ref Assign(ref temp, 0), await Do(i - 1));
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "Assign(ref temp, 0)").WithArguments("C.Assign(ref int, int)").WithLocation(33, 28)
);
}
[Fact]
public void CannotUseAwaitExpressionToAssignRefReturning()
{
var code = @"
using System;
using System.Threading.Tasks;
class TestClass
{
int x = 0;
ref int Save(int y)
{
x = y;
return ref x;
}
void Write(ref int y)
{
Console.WriteLine(y);
}
public int this[int arg]
{
get { return 1; }
set { }
}
public ref int this[int arg, int arg2] => ref x;
async Task TestMethod()
{
Save(1) = await Task.FromResult(0);
var inst = new TestClass();
// valid
inst[1] = await Task.FromResult(1);
// invalid
inst[1, 2] = await Task.FromResult(1);
}
}";
CreateCompilationWithMscorlib461(code).VerifyEmitDiagnostics(
// (28,9): error CS8178: A reference returned by a call to 'TestClass.Save(int)' cannot be preserved across 'await' or 'yield' boundary.
// Save(1) = await Task.FromResult(0);
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "Save(1)").WithArguments("TestClass.Save(int)").WithLocation(28, 9),
// (36,9): error CS8178: A reference returned by a call to 'TestClass.this[int, int].get' cannot be preserved across 'await' or 'yield' boundary.
// inst[1, 2] = await Task.FromResult(1);
Diagnostic(ErrorCode.ERR_RefReturningCallAndAwait, "inst[1, 2]").WithArguments("TestClass.this[int, int].get").WithLocation(36, 9)
);
}
[Fact]
public void RefReadOnlyInAsyncMethodDisallowed()
{
CreateCompilationWithMscorlib461(@"
using System.Threading.Tasks;
class Test
{
async Task Method(in int p)
{
await Task.FromResult(0);
}
}").VerifyDiagnostics(
// (5,30): error CS1988: Async methods cannot have ref, in or out parameters
// async Task Method(in int p)
Diagnostic(ErrorCode.ERR_BadAsyncArgType, "p").WithLocation(5, 30)
);
}
[Fact]
public void RefReadOnlyInIteratorMethodsDisallowed()
{
CreateCompilationWithMscorlib461(@"
using System.Collections.Generic;
class Test
{
IEnumerable<int> Method(in int p)
{
yield return 0;
yield return 1;
yield return 2;
}
}").VerifyDiagnostics(
// (5,36): error CS1623: Iterators cannot have ref, in or out parameters
// IEnumerable<int> Method(in int p)
Diagnostic(ErrorCode.ERR_BadIteratorArgType, "p").WithLocation(5, 36)
);
}
[Fact]
public void RefReadOnlyInEnumeratorMethodsDisallowed()
{
CreateCompilation(@"
using System.Collections.Generic;
class Test
{
public IEnumerator<int> GetEnumerator(in int p)
{
yield return 0;
}
}").VerifyDiagnostics(
// (5,50): error CS1623: Iterators cannot have ref, in or out parameters
// public IEnumerator<int> GetEnumerator(in int p)
Diagnostic(ErrorCode.ERR_BadIteratorArgType, "p").WithLocation(5, 50));
}
[Fact]
public void CannotCallRefReadOnlyMethodsUsingDiscardParameter()
{
CreateCompilation(@"
class Test
{
void M(in int p)
{
}
void N()
{
M(_);
}
}").VerifyDiagnostics(
// (9,11): error CS0103: The name '_' does not exist in the current context
// M(_);
Diagnostic(ErrorCode.ERR_NameNotInContext, "_").WithArguments("_").WithLocation(9, 11));
}
[Fact, WorkItem(26418, "https://github.com/dotnet/roslyn/issues/26418")]
public void OutArgumentsDeclaration_Ref()
{
CreateCompilation(@"
class Test
{
void M(out int p)
{
p = 0;
}
void N()
{
M(out ref int x);
M(out ref var y);
M(out ref int _);
M(out ref var _);
}
}").VerifyDiagnostics(
// (10,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref int x);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref int").WithLocation(10, 15),
// (11,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref var y);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(11, 15),
// (13,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref int _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref int").WithLocation(13, 15),
// (14,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(14, 15));
}
[Fact, WorkItem(26418, "https://github.com/dotnet/roslyn/issues/26418")]
public void OutArgumentsDeclaration_RefReadOnly()
{
CreateCompilation(@"
class Test
{
void M(out int p)
{
p = 0;
}
void N()
{
M(out ref readonly int x);
M(out ref readonly var y);
M(out ref readonly int _);
M(out ref readonly var _);
}
}").VerifyDiagnostics(
// (10,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref readonly int x);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly int").WithLocation(10, 15),
// (11,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref readonly var y);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(11, 15),
// (13,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref readonly int _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly int").WithLocation(13, 15),
// (14,15): error CS8387: An out variable cannot be declared as a ref local
// M(out ref readonly var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref readonly var").WithLocation(14, 15));
}
[Fact, WorkItem(26418, "https://github.com/dotnet/roslyn/issues/26418")]
public void OutArgumentsDeclaration_Out()
{
CreateCompilation(@"
class Test
{
void M(out int p)
{
p = 0;
}
void N()
{
M(out out int x);
}
}").GetParseDiagnostics().Verify(
// (10,15): error CS1525: Invalid expression term 'out'
// M(out out int x);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(10, 15),
// (10,15): error CS1003: Syntax error, ',' expected
// M(out out int x);
Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(10, 15));
}
[Fact, WorkItem(26418, "https://github.com/dotnet/roslyn/issues/26418")]
public void OutArgumentsDeclaration_In()
{
CreateCompilation(@"
class Test
{
void M(out int p)
{
p = 0;
}
void N()
{
M(out in int x);
}
}").GetParseDiagnostics().Verify(
// (10,15): error CS1525: Invalid expression term 'in'
// M(out in int x);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "in").WithArguments("in").WithLocation(10, 15),
// (10,15): error CS1003: Syntax error, ',' expected
// M(out in int x);
Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",").WithLocation(10, 15),
// (10,18): error CS1525: Invalid expression term 'int'
// M(out in int x);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(10, 18),
// (10,22): error CS1003: Syntax error, ',' expected
// M(out in int x);
Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(10, 22));
}
[Fact]
[WorkItem(28117, "https://github.com/dotnet/roslyn/issues/28117")]
public void AssigningRefToParameter()
{
CreateCompilation(@"
public class C
{
void M(int a, ref int b)
{
a = ref b;
}
}").VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// a = ref b;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "a").WithLocation(6, 9));
}
[Fact]
[WorkItem(26516, "https://github.com/dotnet/roslyn/issues/26516")]
public void BindingRefVoidAssignment()
{
CreateCompilation(@"
public class C
{
public void M(ref int x)
{
M(ref void = ref x);
}
}").VerifyDiagnostics(
// (6,12): error CS1525: Invalid expression term 'void'
// M(ref void = ref x);
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "void").WithArguments("void").WithLocation(6, 12));
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_ArrayElement()
{
var compilation = CreateCompilation(@"
public class C
{
public void M(int[] array, ref int value)
{
array[0] = ref value;
}
}").VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// array[0] = ref value;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "array[0]").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((ElementAccessExpressionSyntax)assignment.Left).Expression;
Assert.Equal(SpecialType.System_Int32, ((IArrayTypeSymbol)model.GetTypeInfo(left).Type).ElementType.SpecialType);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_PointerIndirectionOperator()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(int* ptr, ref int value)
{
*ptr = ref value;
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// *ptr = ref value;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "*ptr").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((PrefixUnaryExpressionSyntax)assignment.Left).Operand;
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)model.GetTypeInfo(left).Type).PointedAtType.SpecialType);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_PointerElementAccess()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(int* ptr, ref int value)
{
ptr[0] = ref value;
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// ptr[0] = ref value;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "ptr[0]").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((ElementAccessExpressionSyntax)assignment.Left).Expression;
Assert.Equal(SpecialType.System_Int32, ((IPointerTypeSymbol)model.GetTypeInfo(left).Type).PointedAtType.SpecialType);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_RefvalueExpression()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(int x)
{
__refvalue(__makeref(x), int) = ref x;
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// __refvalue(__makeref(x), int) = ref x;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "__refvalue(__makeref(x), int)").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((MakeRefExpressionSyntax)((RefValueExpressionSyntax)assignment.Left).Expression).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(left).Type.SpecialType);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_DynamicIndexerAccess()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(dynamic d, ref int value)
{
d[0] = ref value;
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// d[0] = ref value;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "d[0]").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((ElementAccessExpressionSyntax)assignment.Left).Expression;
Assert.Equal(SymbolKind.DynamicType, model.GetTypeInfo(left).Type.Kind);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28087, "https://github.com/dotnet/roslyn/issues/28087")]
public void AssigningRef_DynamicMemberAccess()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(dynamic d, ref int value)
{
d.member = ref value;
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (6,9): error CS8373: The left-hand side of a ref assignment must be a ref variable.
// d.member = ref value;
Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "d.member").WithLocation(6, 9));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = ((MemberAccessExpressionSyntax)assignment.Left).Expression;
Assert.Equal(SymbolKind.DynamicType, model.GetTypeInfo(left).Type.Kind);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Fact]
[WorkItem(28238, "https://github.com/dotnet/roslyn/issues/28238")]
public void AssigningRef_TypeExpression()
{
var compilation = CreateCompilation(@"
public unsafe class C
{
public void M(int value)
{
var temp = new
{
object = ref value
};
}
}", options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics(
// (8,13): error CS1525: Invalid expression term 'object'
// object = ref value
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "object").WithArguments("object").WithLocation(8, 13),
// (8,13): error CS0746: Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.
// object = ref value
Diagnostic(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, "object = ref value").WithLocation(8, 13));
var tree = compilation.SyntaxTrees.Single();
var assignment = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);
var left = (PredefinedTypeSyntax)assignment.Left;
Assert.Equal(SpecialType.System_Object, model.GetTypeInfo(left).Type.SpecialType);
var right = ((RefExpressionSyntax)assignment.Right).Expression;
Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(right).Type.SpecialType);
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
[WorkItem(27772, "https://github.com/dotnet/roslyn/issues/27772")]
public void RefReturnInvocationOfRefLikeTypeRefResult(LanguageVersion langVersion)
{
string source = @"
class C
{
public ref long M(S receiver)
{
long x = 0;
ref long y = ref receiver.M(ref x);
return ref y;
}
public ref long M2(S receiver)
{
long x = 0;
{
ref long y = ref receiver.M(ref x);
return ref y;
}
}
}
ref struct S
{
public ref long M(ref long x) => ref x;
}";
var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.RegularDefault.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (8,20): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference
// return ref y;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(8, 20),
// (16,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference
// return ref y;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(16, 24));
}
[Theory]
[InlineData(LanguageVersion.CSharp10)]
[InlineData(LanguageVersion.CSharp11)]
[WorkItem(27772, "https://github.com/dotnet/roslyn/issues/27772")]
public void RefReturnInvocationOfRefLikeTypeRefResult_Repro(LanguageVersion langVersion)
{
string source = @"
using System;
class C
{
static void Main(string[] args)
{
ref long x = ref M(default); // get a reference to the stack which will be used for the next method
M2(ref x); // break things
Console.ReadKey();
}
public static ref long M(S receiver)
{
Span<long> ls = stackalloc long[0]; // change the length of this stackalloc to move the resulting pointer and break different things
long x = 0;
ref var y = ref x;
{
ref var z = ref receiver.M(ref y);
return ref z;
}
}
static void M2(ref long q)
{
Span<long> span = stackalloc long[50];
var element = span[0]; // it was ok
q = -1; // break things
element = span[0]; // and not it's broken:
// System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
}
}
ref struct S
{
public ref long M(ref long x) => ref x;
}";
var comp = CreateCompilationWithMscorlibAndSpan(source, parseOptions: TestOptions.RegularDefault.WithLanguageVersion(langVersion));
comp.VerifyDiagnostics(
// (19,18): error CS8157: Cannot return 'z' by reference because it was initialized to a value that cannot be returned by reference
// return ref z;
Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "z").WithArguments("z").WithLocation(19, 18));
}
[Fact, WorkItem(49617, "https://github.com/dotnet/roslyn/issues/49617")]
public void CannotCallExpressionThatReturnsByRefInExpressionTree_02()
{
var code = @"
class C
{
static void Main()
{
Test2(c => c.P = true);
}
ref bool P => throw null;
static void Test2(System.Linq.Expressions.Expression<System.Action<C>> y){}
}
";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyEmitDiagnostics(
// (6,20): error CS0832: An expression tree may not contain an assignment operator
// Test2(c => c.P = true);
Diagnostic(ErrorCode.ERR_ExpressionTreeContainsAssignment, "c.P = true").WithLocation(6, 20),
// (6,20): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// Test2(c => c.P = true);
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "c.P").WithLocation(6, 20)
);
}
[Fact, WorkItem(49617, "https://github.com/dotnet/roslyn/issues/49617")]
public void CannotCallExpressionThatReturnsByRefInExpressionTree_03()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace RefPropCrash
{
class Program
{
static void Main(string[] args)
{
TestExpression(() => new Model { Value = 1 });
}
static void TestExpression(Expression<Func<Model>> expression)
{
}
}
class Model
{
int value;
public ref int Value => ref value;
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyEmitDiagnostics(
// (11,46): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// TestExpression(() => new Model { Value = 1 });
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "Value").WithLocation(11, 46)
);
}
[Fact, WorkItem(49617, "https://github.com/dotnet/roslyn/issues/49617")]
public void CannotCallExpressionThatReturnsByRefInExpressionTree_04()
{
var code = @"
using System;
using System.Linq.Expressions;
namespace RefPropCrash
{
class Program
{
static void Main(string[] args)
{
TestExpression(() => new Model { 1, 2, 3 });
}
static void TestExpression(Expression<Func<Model>> expression)
{
}
}
class Model : System.Collections.IEnumerable
{
public System.Collections.IEnumerator GetEnumerator() => throw null;
public ref bool Add(int x) => throw null;
}
}";
CreateCompilationWithMscorlib40AndSystemCore(code).VerifyEmitDiagnostics(
// (11,46): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// TestExpression(() => new Model { 1, 2, 3 });
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "1").WithLocation(11, 46),
// (11,49): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// TestExpression(() => new Model { 1, 2, 3 });
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "2").WithLocation(11, 49),
// (11,52): error CS8153: An expression tree lambda may not contain a call to a method, property, or indexer that returns by reference
// TestExpression(() => new Model { 1, 2, 3 });
Diagnostic(ErrorCode.ERR_RefReturningCallInExpressionTree, "3").WithLocation(11, 52)
);
}
[Fact]
public void RefLocalInUsing()
{
var code = @"
var r = new R();
using (ref R r2 = ref r) {}
using ref R r1 = ref r;
struct R : System.IDisposable
{
public void Dispose() {}
}
";
CreateCompilation(code).VerifyEmitDiagnostics(
// (3,8): error CS1073: Unexpected token 'ref'
// using (ref R r2 = ref r) {}
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 8),
// (4,7): error CS1073: Unexpected token 'ref'
// using ref R r1 = ref r;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 7)
);
}
[Fact]
[WorkItem(64259, "https://github.com/dotnet/roslyn/issues/64259")]
public void RefLocalInDeconstruct_01()
{
var code = @"
class C
{
static void Main()
{
int x = 0, y = 0;
(ref int a, ref readonly int b) = (x, y);
}
}
";
CreateCompilation(code).VerifyEmitDiagnostics(
// (7,10): error CS9072: A deconstruction variable cannot be declared as a ref local
// (ref int a, ref readonly int b) = (x, y);
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(7, 10),
// (7,21): error CS9072: A deconstruction variable cannot be declared as a ref local
// (ref int a, ref readonly int b) = (x, y);
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(7, 21)
);
}
[Fact]
[WorkItem(64259, "https://github.com/dotnet/roslyn/issues/64259")]
public void RefLocalInDeconstruct_02()
{
var code = @"
class C
{
static void Main()
{
int x = 0, y = 0, z = 0;
(ref var a, ref var (b, c)) = (x, (y, z));
(ref int d, var e) = (x, y);
}
}
";
var comp = CreateCompilation(code).VerifyEmitDiagnostics(
// (7,10): error CS9072: A deconstruction variable cannot be declared as a ref local
// (ref var a, ref var (b, c)) = (x, (y, z));
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(7, 10),
// (7,21): error CS1525: Invalid expression term 'ref'
// (ref var a, ref var (b, c)) = (x, (y, z));
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref var (b, c)").WithArguments("ref").WithLocation(7, 21),
// (7,21): error CS1073: Unexpected token 'ref'
// (ref var a, ref var (b, c)) = (x, (y, z));
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 21),
// (8,10): error CS9072: A deconstruction variable cannot be declared as a ref local
// (ref int d, var e) = (x, y);
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(8, 10)
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<DeclarationExpressionSyntax>().ToArray();
foreach (var decl in decls)
{
var type = decl.Type;
if (type is RefTypeSyntax refType)
{
Assert.Null(model.GetSymbolInfo(type).Symbol);
Assert.Null(model.GetTypeInfo(type).Type);
type = refType.Type;
}
Assert.Equal("System.Int32", model.GetSymbolInfo(type).Symbol.ToTestDisplayString());
Assert.Equal("System.Int32", model.GetTypeInfo(type).Type.ToTestDisplayString());
}
}
[Fact]
[WorkItem(64259, "https://github.com/dotnet/roslyn/issues/64259")]
public void RefLocalInDeconstruct_03()
{
var code = @"
int x = 0, y = 0, z = 0;
(ref var d, var e) = (x, y);
(ref int f, ref var _) = (x, y);
";
var comp = CreateCompilation(code, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script);
comp.VerifyEmitDiagnostics(
// (3,2): error CS1073: Unexpected token 'ref'
// (ref var d, var e) = (x, y);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 2),
// (4,2): error CS1073: Unexpected token 'ref'
// (ref int f, ref var _) = (x, y);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 2),
// (4,13): error CS9072: A deconstruction variable cannot be declared as a ref local
// (ref int f, ref var _) = (x, y);
Diagnostic(ErrorCode.ERR_DeconstructVariableCannotBeByRef, "ref").WithLocation(4, 13)
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
Assert.Equal(3, decls.Length);
foreach (var decl in decls)
{
var f = model.GetDeclaredSymbol(decl).GetSymbol<FieldSymbol>();
Assert.Equal(RefKind.None, f.RefKind);
Assert.Equal("System.Int32", f.Type.ToTestDisplayString());
}
}
[Fact]
public void RefLocalInOutVar_01()
{
var code = @"
M(out ref var a);
M(out ref int b);
M(out ref var _);
void M(out int x) => throw null;
";
var comp = CreateCompilation(code, options: TestOptions.ReleaseExe.WithScriptClassName("Script"), parseOptions: TestOptions.Script);
comp.VerifyEmitDiagnostics(
// (2,7): error CS1073: Unexpected token 'ref'
// M(out ref var a);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(2, 7),
// (3,7): error CS1073: Unexpected token 'ref'
// M(out ref int b);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(3, 7),
// (4,7): error CS8388: An out variable cannot be declared as a ref local
// M(out ref var _);
Diagnostic(ErrorCode.ERR_OutVariableCannotBeByRef, "ref var").WithLocation(4, 7)
);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var decls = tree.GetRoot().DescendantNodes().OfType<SingleVariableDesignationSyntax>().ToArray();
Assert.Equal(2, decls.Length);
foreach (var decl in decls)
{
var f = model.GetDeclaredSymbol(decl).GetSymbol<FieldSymbol>();
Assert.Equal(RefKind.None, f.RefKind);
Assert.Equal("System.Int32", f.Type.ToTestDisplayString());
}
}
}
}
|